K-Means Clustering#
K-Means clustering merupakan salah satu metode dalam unsupervised learning yang digunakan untuk mengelompokkan data ke dalam beberapa kelompok (cluster) berdasarkan kesamaan karakteristik atau fitur. Tujuan utamanya adalah untuk membagi data ke dalam K kelompok yang saling terpisah, dimana dalam kelompok data bersifat homogen dan antar kelompok data bersifat heterogen.
Langkah-langkah algoritma K-Means :#
Menentukan jumlah kluster sebanyak \(K\)
Artinya menentukan berapa banyak kelompok/kluster yang ingin dibuat dari data. Misalnya \(K\) = 3 maka membagi data menjadi 3 kluster.
Pemilihan nilai \(K\) dapat menggunakan metode seperti Elbow Method untuk membantu menentukan \(K\) yang optimal.
Memilih K centroid awal secara acak
Artinya menentukan titik awal (centroid) sebagai pusat dari masing-masing kluster.
Centroid bisa dipilih secara acak dari data yang ada atau menggunakan teknik seperti K-Means++ dimana dijalankan secara otomatis pada scikit-learn untuk hasil centroid yang lebih baik.
Menghitung jarak setiap data ke tiap centroid
Artinya menentukan seberapa dekat setiap data ke setiap centroid.
Umumnya menggunakan Euclidian distance.
Mengelompokkan data berdasarkan centroid terdekat
Artinya mengklasifikasikan setiap data ke dalam salah satu dari \(K\) kluster.
Setiap data ditempatkan ke kluster yang pusatnya (centroid-nya) paling dekat dengannya. Jadi, tiap data hanya masuk ke satu kluster.
Menghitung rata-rata dari anggota kluster, untuk menemukan centroid baru
Menentukan pusat kluster baru berdasarkan data yang saat ini berada dalam kluster tersebut.
Centroid baru adalah rata-rata dari semua data di dalam suatu kluster.
Mengulang langkah nomor 3-5 sampai data pada setiap kluster tidak berubah signifikan.
Iterasi dilakukan sampai tidak ada lagi data yang berpindah kluster, atau perubahan posisi centroid sangat kecil.
Evaluasi Hasil K-Means#
Inertia (Sum Square Error/SSE)
Inertia mengukur sejauh mana titik data dalam suatu cluster tersebar dari pusat cluster tersebut. Semakin kecil nilai inertia, klaster semakin baik.
Keterangan :
\(x_i\) : Titik data ke-\(i\)
\(\mu_{c_i}\) : Centroid dari cluster tempat \(x_i\) berada
Nilai inertia (sangat kecil/mendekati 0) : Klaster sangat kompak dan semua titik dekat dengan centroidnya (sangat baik).
Nilai inertia (kecil-sedang) : Klaster cukup baik dan dapat diterima dalam banyak kasus.
Nilai inertia (besar) : Klaster tidak rapat, data menyebar jauh dari centroid → bisa jadi jumlah klaster (k) kurang tepat atau K-Means tidak cocok digunakan.
Silhouette Method : Sebuah metode yang mengukur tingkat kemiripan suatu point dengan clusternya dibandingkan dengan kluster lain.
untuk setiap titik \(i\), silhouette (\(i\)) dihitung sebagai :
Keterangan :
\(a(i)\) : rata-rata jarak titik \(i\) ke semua titik lain dalam klaster yang sama.
\(b(i)\) : rata-rata jarak titik \(i\) ke semua titik dalam klaster terdekat (tetangga).
Nilai silhouette mendekati angka 1 artinya suatu data berada pada cluster yang benar dengan jarak jauh dari cluster lain.
Nilai silhouette negatif artinya data tersebut lebih baik berada di kluster lain daripada kluster saat ini.
Nilai silhouette = 0, artinya data tersebut di perbatasan antara dua cluster.
Komputasi K-Means Data IRIS#
2 Klaster#
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import silhouette_score, accuracy_score, confusion_matrix
import pandas as pd
# Baca data fitur dan label
df_features = pd.read_excel("data_iris.xlsx")
df_class = pd.read_excel("class.xlsx") # kolom 'class'
df = df_features.copy()
df['class'] = df_class['class']
# Ambil fitur untuk clustering
features = df[['sepal_length', 'sepal_width', 'petal_length', 'petal_width']]
# Normalisasi fitur(MinMax)
scaler = MinMaxScaler()
scaled_features = scaler.fit_transform(features)
# KMeans clustering
K = 2
kmeans = KMeans(n_clusters=K, max_iter=300, tol=0.0001, random_state=42, n_init='auto')
kmeans.fit(scaled_features)
df['cluster'] = kmeans.labels_
print(f"Jumlah iterasi sampai konvergen: {kmeans.n_iter_}")
print(f"Inertia (SSE): {kmeans.inertia_:.4f}")
sil_score = silhouette_score(scaled_features, kmeans.labels_)
print(f"Silhouette Score: {sil_score:.4f}")
# Mapping cluster ke class mayoritas
mapping = (
df.groupby('cluster')['class']
.agg(lambda x: x.mode()[0])
.to_dict()
)
df['predicted_class'] = df['cluster'].map(mapping)
# Evaluasi
y_true = df['class']
y_pred = df['predicted_class']
acc = accuracy_score(y_true, y_pred)
print(f"\nAkurasi keseluruhan clustering terhadap label asli: {acc:.4%}")
# Distribusi cluster per kelas (untuk insight)
dist = pd.crosstab(df['class'], df['cluster'], rownames=['Class'], colnames=['Cluster'])
print("\nDistribusi cluster per kelas:")
print(dist)
# Simpan hasil ke Excel
df.to_excel("hasil2.xlsx", index=False)
# Kalau ingin tampil semua baris (hati-hati jika data sangat banyak)
pd.set_option('display.max_rows', None)
print(df[['class', 'cluster', 'predicted_class']])
Jumlah iterasi sampai konvergen: 4
Inertia (SSE): 12.1437
Silhouette Score: 0.6295
Akurasi keseluruhan clustering terhadap label asli: 66.6667%
Distribusi cluster per kelas:
Cluster 0 1
Class
Iris-setosa 0 50
Iris-versicolor 50 0
Iris-virginica 50 0
class cluster predicted_class
0 Iris-setosa 1 Iris-setosa
1 Iris-setosa 1 Iris-setosa
2 Iris-setosa 1 Iris-setosa
3 Iris-setosa 1 Iris-setosa
4 Iris-setosa 1 Iris-setosa
5 Iris-setosa 1 Iris-setosa
6 Iris-setosa 1 Iris-setosa
7 Iris-setosa 1 Iris-setosa
8 Iris-setosa 1 Iris-setosa
9 Iris-setosa 1 Iris-setosa
10 Iris-setosa 1 Iris-setosa
11 Iris-setosa 1 Iris-setosa
12 Iris-setosa 1 Iris-setosa
13 Iris-setosa 1 Iris-setosa
14 Iris-setosa 1 Iris-setosa
15 Iris-setosa 1 Iris-setosa
16 Iris-setosa 1 Iris-setosa
17 Iris-setosa 1 Iris-setosa
18 Iris-setosa 1 Iris-setosa
19 Iris-setosa 1 Iris-setosa
20 Iris-setosa 1 Iris-setosa
21 Iris-setosa 1 Iris-setosa
22 Iris-setosa 1 Iris-setosa
23 Iris-setosa 1 Iris-setosa
24 Iris-setosa 1 Iris-setosa
25 Iris-setosa 1 Iris-setosa
26 Iris-setosa 1 Iris-setosa
27 Iris-setosa 1 Iris-setosa
28 Iris-setosa 1 Iris-setosa
29 Iris-setosa 1 Iris-setosa
30 Iris-setosa 1 Iris-setosa
31 Iris-setosa 1 Iris-setosa
32 Iris-setosa 1 Iris-setosa
33 Iris-setosa 1 Iris-setosa
34 Iris-setosa 1 Iris-setosa
35 Iris-setosa 1 Iris-setosa
36 Iris-setosa 1 Iris-setosa
37 Iris-setosa 1 Iris-setosa
38 Iris-setosa 1 Iris-setosa
39 Iris-setosa 1 Iris-setosa
40 Iris-setosa 1 Iris-setosa
41 Iris-setosa 1 Iris-setosa
42 Iris-setosa 1 Iris-setosa
43 Iris-setosa 1 Iris-setosa
44 Iris-setosa 1 Iris-setosa
45 Iris-setosa 1 Iris-setosa
46 Iris-setosa 1 Iris-setosa
47 Iris-setosa 1 Iris-setosa
48 Iris-setosa 1 Iris-setosa
49 Iris-setosa 1 Iris-setosa
50 Iris-versicolor 0 Iris-versicolor
51 Iris-versicolor 0 Iris-versicolor
52 Iris-versicolor 0 Iris-versicolor
53 Iris-versicolor 0 Iris-versicolor
54 Iris-versicolor 0 Iris-versicolor
55 Iris-versicolor 0 Iris-versicolor
56 Iris-versicolor 0 Iris-versicolor
57 Iris-versicolor 0 Iris-versicolor
58 Iris-versicolor 0 Iris-versicolor
59 Iris-versicolor 0 Iris-versicolor
60 Iris-versicolor 0 Iris-versicolor
61 Iris-versicolor 0 Iris-versicolor
62 Iris-versicolor 0 Iris-versicolor
63 Iris-versicolor 0 Iris-versicolor
64 Iris-versicolor 0 Iris-versicolor
65 Iris-versicolor 0 Iris-versicolor
66 Iris-versicolor 0 Iris-versicolor
67 Iris-versicolor 0 Iris-versicolor
68 Iris-versicolor 0 Iris-versicolor
69 Iris-versicolor 0 Iris-versicolor
70 Iris-versicolor 0 Iris-versicolor
71 Iris-versicolor 0 Iris-versicolor
72 Iris-versicolor 0 Iris-versicolor
73 Iris-versicolor 0 Iris-versicolor
74 Iris-versicolor 0 Iris-versicolor
75 Iris-versicolor 0 Iris-versicolor
76 Iris-versicolor 0 Iris-versicolor
77 Iris-versicolor 0 Iris-versicolor
78 Iris-versicolor 0 Iris-versicolor
79 Iris-versicolor 0 Iris-versicolor
80 Iris-versicolor 0 Iris-versicolor
81 Iris-versicolor 0 Iris-versicolor
82 Iris-versicolor 0 Iris-versicolor
83 Iris-versicolor 0 Iris-versicolor
84 Iris-versicolor 0 Iris-versicolor
85 Iris-versicolor 0 Iris-versicolor
86 Iris-versicolor 0 Iris-versicolor
87 Iris-versicolor 0 Iris-versicolor
88 Iris-versicolor 0 Iris-versicolor
89 Iris-versicolor 0 Iris-versicolor
90 Iris-versicolor 0 Iris-versicolor
91 Iris-versicolor 0 Iris-versicolor
92 Iris-versicolor 0 Iris-versicolor
93 Iris-versicolor 0 Iris-versicolor
94 Iris-versicolor 0 Iris-versicolor
95 Iris-versicolor 0 Iris-versicolor
96 Iris-versicolor 0 Iris-versicolor
97 Iris-versicolor 0 Iris-versicolor
98 Iris-versicolor 0 Iris-versicolor
99 Iris-versicolor 0 Iris-versicolor
100 Iris-virginica 0 Iris-versicolor
101 Iris-virginica 0 Iris-versicolor
102 Iris-virginica 0 Iris-versicolor
103 Iris-virginica 0 Iris-versicolor
104 Iris-virginica 0 Iris-versicolor
105 Iris-virginica 0 Iris-versicolor
106 Iris-virginica 0 Iris-versicolor
107 Iris-virginica 0 Iris-versicolor
108 Iris-virginica 0 Iris-versicolor
109 Iris-virginica 0 Iris-versicolor
110 Iris-virginica 0 Iris-versicolor
111 Iris-virginica 0 Iris-versicolor
112 Iris-virginica 0 Iris-versicolor
113 Iris-virginica 0 Iris-versicolor
114 Iris-virginica 0 Iris-versicolor
115 Iris-virginica 0 Iris-versicolor
116 Iris-virginica 0 Iris-versicolor
117 Iris-virginica 0 Iris-versicolor
118 Iris-virginica 0 Iris-versicolor
119 Iris-virginica 0 Iris-versicolor
120 Iris-virginica 0 Iris-versicolor
121 Iris-virginica 0 Iris-versicolor
122 Iris-virginica 0 Iris-versicolor
123 Iris-virginica 0 Iris-versicolor
124 Iris-virginica 0 Iris-versicolor
125 Iris-virginica 0 Iris-versicolor
126 Iris-virginica 0 Iris-versicolor
127 Iris-virginica 0 Iris-versicolor
128 Iris-virginica 0 Iris-versicolor
129 Iris-virginica 0 Iris-versicolor
130 Iris-virginica 0 Iris-versicolor
131 Iris-virginica 0 Iris-versicolor
132 Iris-virginica 0 Iris-versicolor
133 Iris-virginica 0 Iris-versicolor
134 Iris-virginica 0 Iris-versicolor
135 Iris-virginica 0 Iris-versicolor
136 Iris-virginica 0 Iris-versicolor
137 Iris-virginica 0 Iris-versicolor
138 Iris-virginica 0 Iris-versicolor
139 Iris-virginica 0 Iris-versicolor
140 Iris-virginica 0 Iris-versicolor
141 Iris-virginica 0 Iris-versicolor
142 Iris-virginica 0 Iris-versicolor
143 Iris-virginica 0 Iris-versicolor
144 Iris-virginica 0 Iris-versicolor
145 Iris-virginica 0 Iris-versicolor
146 Iris-virginica 0 Iris-versicolor
147 Iris-virginica 0 Iris-versicolor
148 Iris-virginica 0 Iris-versicolor
149 Iris-virginica 0 Iris-versicolor
3 Klaster#
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import silhouette_score, accuracy_score, confusion_matrix
import pandas as pd
# Baca data fitur dan label
df_features = pd.read_excel("data_iris.xlsx")
df_class = pd.read_excel("class.xlsx") # kolom 'class'
df = df_features.copy()
df['class'] = df_class['class']
# Ambil fitur untuk clustering
features = df[['sepal_length', 'sepal_width', 'petal_length', 'petal_width']]
# Normalisasi fitur (MinMax)
scaler = MinMaxScaler()
scaled_features = scaler.fit_transform(features)
# KMeans clustering
K = 3
kmeans = KMeans(
n_clusters=K,
max_iter=300,
tol=0.0001,
random_state=42,
n_init='auto' # ganti ke 10 jika sklearn <1.4
)
kmeans.fit(scaled_features)
df['cluster'] = kmeans.labels_
# Cetak metrik clustering
print(f"Jumlah iterasi sampai konvergen: {kmeans.n_iter_}")
print(f"Inertia (SSE): {kmeans.inertia_:.4f}")
sil_score = silhouette_score(scaled_features, kmeans.labels_)
print(f"Silhouette Score: {sil_score:.4f}")
# Mapping cluster ke class mayoritas
mapping = (
df.groupby('cluster')['class']
.agg(lambda x: x.mode()[0])
.to_dict()
)
df['predicted_class'] = df['cluster'].map(mapping)
# Siapkan untuk evaluasi
y_true = df['class']
y_pred = df['predicted_class']
classes = sorted(df['class'].unique())
cm = confusion_matrix(y_true, y_pred, labels=classes)
# Akurasi keseluruhan
acc = accuracy_score(y_true, y_pred)
print(f"\nAkurasi keseluruhan clustering terhadap label asli: {acc:.4%}")
# Persentase error per kelas
error_per_class = {}
for i, c in enumerate(classes):
total = cm[i].sum()
correct = cm[i, i]
error = 1 - correct/total if total > 0 else 0
error_per_class[c] = error
print("\nPersentase kesalahan per kelas:")
for c, e in error_per_class.items():
print(f" - {c}: {e:.2%}")
# Distribusi cluster per kelas (insight)
dist = pd.crosstab(df['class'], df['cluster'],
rownames=['Class'], colnames=['Cluster'])
print("\nDistribusi cluster per kelas:")
print(dist)
# Simpan hasil lengkap ke Excel
df.to_excel("hasil_clustering_dengan_class_lengkap.xlsx", index=False)
# Tampilkan perbandingan class vs cluster vs predicted_class
pd.set_option('display.max_rows', None)
print("\nPerbandingan lengkap:")
print(df[['class', 'cluster', 'predicted_class']])
Jumlah iterasi sampai konvergen: 3
Inertia (SSE): 7.1386
Silhouette Score: 0.4825
Akurasi keseluruhan clustering terhadap label asli: 88.0000%
Persentase kesalahan per kelas:
- Iris-setosa: 0.00%
- Iris-versicolor: 20.00%
- Iris-virginica: 16.00%
Distribusi cluster per kelas:
Cluster 0 1 2
Class
Iris-setosa 0 50 0
Iris-versicolor 10 0 40
Iris-virginica 42 0 8
Perbandingan lengkap:
class cluster predicted_class
0 Iris-setosa 1 Iris-setosa
1 Iris-setosa 1 Iris-setosa
2 Iris-setosa 1 Iris-setosa
3 Iris-setosa 1 Iris-setosa
4 Iris-setosa 1 Iris-setosa
5 Iris-setosa 1 Iris-setosa
6 Iris-setosa 1 Iris-setosa
7 Iris-setosa 1 Iris-setosa
8 Iris-setosa 1 Iris-setosa
9 Iris-setosa 1 Iris-setosa
10 Iris-setosa 1 Iris-setosa
11 Iris-setosa 1 Iris-setosa
12 Iris-setosa 1 Iris-setosa
13 Iris-setosa 1 Iris-setosa
14 Iris-setosa 1 Iris-setosa
15 Iris-setosa 1 Iris-setosa
16 Iris-setosa 1 Iris-setosa
17 Iris-setosa 1 Iris-setosa
18 Iris-setosa 1 Iris-setosa
19 Iris-setosa 1 Iris-setosa
20 Iris-setosa 1 Iris-setosa
21 Iris-setosa 1 Iris-setosa
22 Iris-setosa 1 Iris-setosa
23 Iris-setosa 1 Iris-setosa
24 Iris-setosa 1 Iris-setosa
25 Iris-setosa 1 Iris-setosa
26 Iris-setosa 1 Iris-setosa
27 Iris-setosa 1 Iris-setosa
28 Iris-setosa 1 Iris-setosa
29 Iris-setosa 1 Iris-setosa
30 Iris-setosa 1 Iris-setosa
31 Iris-setosa 1 Iris-setosa
32 Iris-setosa 1 Iris-setosa
33 Iris-setosa 1 Iris-setosa
34 Iris-setosa 1 Iris-setosa
35 Iris-setosa 1 Iris-setosa
36 Iris-setosa 1 Iris-setosa
37 Iris-setosa 1 Iris-setosa
38 Iris-setosa 1 Iris-setosa
39 Iris-setosa 1 Iris-setosa
40 Iris-setosa 1 Iris-setosa
41 Iris-setosa 1 Iris-setosa
42 Iris-setosa 1 Iris-setosa
43 Iris-setosa 1 Iris-setosa
44 Iris-setosa 1 Iris-setosa
45 Iris-setosa 1 Iris-setosa
46 Iris-setosa 1 Iris-setosa
47 Iris-setosa 1 Iris-setosa
48 Iris-setosa 1 Iris-setosa
49 Iris-setosa 1 Iris-setosa
50 Iris-versicolor 0 Iris-virginica
51 Iris-versicolor 0 Iris-virginica
52 Iris-versicolor 0 Iris-virginica
53 Iris-versicolor 2 Iris-versicolor
54 Iris-versicolor 2 Iris-versicolor
55 Iris-versicolor 2 Iris-versicolor
56 Iris-versicolor 0 Iris-virginica
57 Iris-versicolor 2 Iris-versicolor
58 Iris-versicolor 2 Iris-versicolor
59 Iris-versicolor 2 Iris-versicolor
60 Iris-versicolor 2 Iris-versicolor
61 Iris-versicolor 2 Iris-versicolor
62 Iris-versicolor 2 Iris-versicolor
63 Iris-versicolor 2 Iris-versicolor
64 Iris-versicolor 2 Iris-versicolor
65 Iris-versicolor 0 Iris-virginica
66 Iris-versicolor 2 Iris-versicolor
67 Iris-versicolor 2 Iris-versicolor
68 Iris-versicolor 2 Iris-versicolor
69 Iris-versicolor 2 Iris-versicolor
70 Iris-versicolor 0 Iris-virginica
71 Iris-versicolor 2 Iris-versicolor
72 Iris-versicolor 2 Iris-versicolor
73 Iris-versicolor 2 Iris-versicolor
74 Iris-versicolor 2 Iris-versicolor
75 Iris-versicolor 2 Iris-versicolor
76 Iris-versicolor 0 Iris-virginica
77 Iris-versicolor 0 Iris-virginica
78 Iris-versicolor 2 Iris-versicolor
79 Iris-versicolor 2 Iris-versicolor
80 Iris-versicolor 2 Iris-versicolor
81 Iris-versicolor 2 Iris-versicolor
82 Iris-versicolor 2 Iris-versicolor
83 Iris-versicolor 2 Iris-versicolor
84 Iris-versicolor 2 Iris-versicolor
85 Iris-versicolor 0 Iris-virginica
86 Iris-versicolor 0 Iris-virginica
87 Iris-versicolor 2 Iris-versicolor
88 Iris-versicolor 2 Iris-versicolor
89 Iris-versicolor 2 Iris-versicolor
90 Iris-versicolor 2 Iris-versicolor
91 Iris-versicolor 2 Iris-versicolor
92 Iris-versicolor 2 Iris-versicolor
93 Iris-versicolor 2 Iris-versicolor
94 Iris-versicolor 2 Iris-versicolor
95 Iris-versicolor 2 Iris-versicolor
96 Iris-versicolor 2 Iris-versicolor
97 Iris-versicolor 2 Iris-versicolor
98 Iris-versicolor 2 Iris-versicolor
99 Iris-versicolor 2 Iris-versicolor
100 Iris-virginica 0 Iris-virginica
101 Iris-virginica 2 Iris-versicolor
102 Iris-virginica 0 Iris-virginica
103 Iris-virginica 0 Iris-virginica
104 Iris-virginica 0 Iris-virginica
105 Iris-virginica 0 Iris-virginica
106 Iris-virginica 2 Iris-versicolor
107 Iris-virginica 0 Iris-virginica
108 Iris-virginica 0 Iris-virginica
109 Iris-virginica 0 Iris-virginica
110 Iris-virginica 0 Iris-virginica
111 Iris-virginica 0 Iris-virginica
112 Iris-virginica 0 Iris-virginica
113 Iris-virginica 2 Iris-versicolor
114 Iris-virginica 0 Iris-virginica
115 Iris-virginica 0 Iris-virginica
116 Iris-virginica 0 Iris-virginica
117 Iris-virginica 0 Iris-virginica
118 Iris-virginica 0 Iris-virginica
119 Iris-virginica 2 Iris-versicolor
120 Iris-virginica 0 Iris-virginica
121 Iris-virginica 2 Iris-versicolor
122 Iris-virginica 0 Iris-virginica
123 Iris-virginica 0 Iris-virginica
124 Iris-virginica 0 Iris-virginica
125 Iris-virginica 0 Iris-virginica
126 Iris-virginica 0 Iris-virginica
127 Iris-virginica 0 Iris-virginica
128 Iris-virginica 0 Iris-virginica
129 Iris-virginica 0 Iris-virginica
130 Iris-virginica 0 Iris-virginica
131 Iris-virginica 0 Iris-virginica
132 Iris-virginica 0 Iris-virginica
133 Iris-virginica 2 Iris-versicolor
134 Iris-virginica 2 Iris-versicolor
135 Iris-virginica 0 Iris-virginica
136 Iris-virginica 0 Iris-virginica
137 Iris-virginica 0 Iris-virginica
138 Iris-virginica 0 Iris-virginica
139 Iris-virginica 0 Iris-virginica
140 Iris-virginica 0 Iris-virginica
141 Iris-virginica 0 Iris-virginica
142 Iris-virginica 2 Iris-versicolor
143 Iris-virginica 0 Iris-virginica
144 Iris-virginica 0 Iris-virginica
145 Iris-virginica 0 Iris-virginica
146 Iris-virginica 0 Iris-virginica
147 Iris-virginica 0 Iris-virginica
148 Iris-virginica 0 Iris-virginica
149 Iris-virginica 0 Iris-virginica
4 Klaster#
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import silhouette_score, accuracy_score, confusion_matrix
import pandas as pd
# Baca data fitur dan label
df_features = pd.read_excel("data_iris.xlsx")
df_class = pd.read_excel("class.xlsx") # kolom 'class'
df = df_features.copy()
df['class'] = df_class['class']
# Ambil fitur untuk clustering
features = df[['sepal_length', 'sepal_width', 'petal_length', 'petal_width']]
# Normalisasi fitur(MinMax)
scaler = MinMaxScaler()
scaled_features = scaler.fit_transform(features)
# KMeans clustering
K = 4
kmeans = KMeans(n_clusters=K, max_iter=300, tol=0.0001, random_state=42, n_init='auto')
kmeans.fit(scaled_features)
df['cluster'] = kmeans.labels_
print(f"Jumlah iterasi sampai konvergen: {kmeans.n_iter_}")
print(f"Inertia (SSE): {kmeans.inertia_:.4f}")
sil_score = silhouette_score(scaled_features, kmeans.labels_)
print(f"Silhouette Score: {sil_score:.4f}")
# Mapping cluster ke class mayoritas
mapping = (
df.groupby('cluster')['class']
.agg(lambda x: x.mode()[0])
.to_dict()
)
df['predicted_class'] = df['cluster'].map(mapping)
# Evaluasi
y_true = df['class']
y_pred = df['predicted_class']
acc = accuracy_score(y_true, y_pred)
print(f"\nAkurasi keseluruhan clustering terhadap label asli: {acc:.4%}")
# Distribusi cluster per kelas (untuk insight)
dist = pd.crosstab(df['class'], df['cluster'], rownames=['Class'], colnames=['Cluster'])
print("\nDistribusi cluster per kelas:")
print(dist)
# Simpan hasil ke Excel
df.to_excel("hasil4.xlsx", index=False)
# Kalau ingin tampil semua baris (hati-hati jika data sangat banyak)
pd.set_option('display.max_rows', None)
print(df[['class', 'cluster', 'predicted_class']])
Jumlah iterasi sampai konvergen: 6
Inertia (SSE): 5.5417
Silhouette Score: 0.4435
Akurasi keseluruhan clustering terhadap label asli: 84.6667%
Distribusi cluster per kelas:
Cluster 0 1 2 3
Class
Iris-setosa 0 50 0 0
Iris-versicolor 21 0 29 0
Iris-virginica 21 0 2 27
class cluster predicted_class
0 Iris-setosa 1 Iris-setosa
1 Iris-setosa 1 Iris-setosa
2 Iris-setosa 1 Iris-setosa
3 Iris-setosa 1 Iris-setosa
4 Iris-setosa 1 Iris-setosa
5 Iris-setosa 1 Iris-setosa
6 Iris-setosa 1 Iris-setosa
7 Iris-setosa 1 Iris-setosa
8 Iris-setosa 1 Iris-setosa
9 Iris-setosa 1 Iris-setosa
10 Iris-setosa 1 Iris-setosa
11 Iris-setosa 1 Iris-setosa
12 Iris-setosa 1 Iris-setosa
13 Iris-setosa 1 Iris-setosa
14 Iris-setosa 1 Iris-setosa
15 Iris-setosa 1 Iris-setosa
16 Iris-setosa 1 Iris-setosa
17 Iris-setosa 1 Iris-setosa
18 Iris-setosa 1 Iris-setosa
19 Iris-setosa 1 Iris-setosa
20 Iris-setosa 1 Iris-setosa
21 Iris-setosa 1 Iris-setosa
22 Iris-setosa 1 Iris-setosa
23 Iris-setosa 1 Iris-setosa
24 Iris-setosa 1 Iris-setosa
25 Iris-setosa 1 Iris-setosa
26 Iris-setosa 1 Iris-setosa
27 Iris-setosa 1 Iris-setosa
28 Iris-setosa 1 Iris-setosa
29 Iris-setosa 1 Iris-setosa
30 Iris-setosa 1 Iris-setosa
31 Iris-setosa 1 Iris-setosa
32 Iris-setosa 1 Iris-setosa
33 Iris-setosa 1 Iris-setosa
34 Iris-setosa 1 Iris-setosa
35 Iris-setosa 1 Iris-setosa
36 Iris-setosa 1 Iris-setosa
37 Iris-setosa 1 Iris-setosa
38 Iris-setosa 1 Iris-setosa
39 Iris-setosa 1 Iris-setosa
40 Iris-setosa 1 Iris-setosa
41 Iris-setosa 1 Iris-setosa
42 Iris-setosa 1 Iris-setosa
43 Iris-setosa 1 Iris-setosa
44 Iris-setosa 1 Iris-setosa
45 Iris-setosa 1 Iris-setosa
46 Iris-setosa 1 Iris-setosa
47 Iris-setosa 1 Iris-setosa
48 Iris-setosa 1 Iris-setosa
49 Iris-setosa 1 Iris-setosa
50 Iris-versicolor 0 Iris-versicolor
51 Iris-versicolor 0 Iris-versicolor
52 Iris-versicolor 0 Iris-versicolor
53 Iris-versicolor 2 Iris-versicolor
54 Iris-versicolor 0 Iris-versicolor
55 Iris-versicolor 2 Iris-versicolor
56 Iris-versicolor 0 Iris-versicolor
57 Iris-versicolor 2 Iris-versicolor
58 Iris-versicolor 0 Iris-versicolor
59 Iris-versicolor 2 Iris-versicolor
60 Iris-versicolor 2 Iris-versicolor
61 Iris-versicolor 0 Iris-versicolor
62 Iris-versicolor 2 Iris-versicolor
63 Iris-versicolor 0 Iris-versicolor
64 Iris-versicolor 2 Iris-versicolor
65 Iris-versicolor 0 Iris-versicolor
66 Iris-versicolor 2 Iris-versicolor
67 Iris-versicolor 2 Iris-versicolor
68 Iris-versicolor 2 Iris-versicolor
69 Iris-versicolor 2 Iris-versicolor
70 Iris-versicolor 0 Iris-versicolor
71 Iris-versicolor 2 Iris-versicolor
72 Iris-versicolor 0 Iris-versicolor
73 Iris-versicolor 2 Iris-versicolor
74 Iris-versicolor 0 Iris-versicolor
75 Iris-versicolor 0 Iris-versicolor
76 Iris-versicolor 0 Iris-versicolor
77 Iris-versicolor 0 Iris-versicolor
78 Iris-versicolor 0 Iris-versicolor
79 Iris-versicolor 2 Iris-versicolor
80 Iris-versicolor 2 Iris-versicolor
81 Iris-versicolor 2 Iris-versicolor
82 Iris-versicolor 2 Iris-versicolor
83 Iris-versicolor 0 Iris-versicolor
84 Iris-versicolor 2 Iris-versicolor
85 Iris-versicolor 0 Iris-versicolor
86 Iris-versicolor 0 Iris-versicolor
87 Iris-versicolor 2 Iris-versicolor
88 Iris-versicolor 2 Iris-versicolor
89 Iris-versicolor 2 Iris-versicolor
90 Iris-versicolor 2 Iris-versicolor
91 Iris-versicolor 0 Iris-versicolor
92 Iris-versicolor 2 Iris-versicolor
93 Iris-versicolor 2 Iris-versicolor
94 Iris-versicolor 2 Iris-versicolor
95 Iris-versicolor 2 Iris-versicolor
96 Iris-versicolor 2 Iris-versicolor
97 Iris-versicolor 0 Iris-versicolor
98 Iris-versicolor 2 Iris-versicolor
99 Iris-versicolor 2 Iris-versicolor
100 Iris-virginica 3 Iris-virginica
101 Iris-virginica 0 Iris-versicolor
102 Iris-virginica 3 Iris-virginica
103 Iris-virginica 0 Iris-versicolor
104 Iris-virginica 3 Iris-virginica
105 Iris-virginica 3 Iris-virginica
106 Iris-virginica 2 Iris-versicolor
107 Iris-virginica 3 Iris-virginica
108 Iris-virginica 0 Iris-versicolor
109 Iris-virginica 3 Iris-virginica
110 Iris-virginica 0 Iris-versicolor
111 Iris-virginica 0 Iris-versicolor
112 Iris-virginica 3 Iris-virginica
113 Iris-virginica 0 Iris-versicolor
114 Iris-virginica 0 Iris-versicolor
115 Iris-virginica 3 Iris-virginica
116 Iris-virginica 0 Iris-versicolor
117 Iris-virginica 3 Iris-virginica
118 Iris-virginica 3 Iris-virginica
119 Iris-virginica 2 Iris-versicolor
120 Iris-virginica 3 Iris-virginica
121 Iris-virginica 0 Iris-versicolor
122 Iris-virginica 3 Iris-virginica
123 Iris-virginica 0 Iris-versicolor
124 Iris-virginica 3 Iris-virginica
125 Iris-virginica 3 Iris-virginica
126 Iris-virginica 0 Iris-versicolor
127 Iris-virginica 0 Iris-versicolor
128 Iris-virginica 0 Iris-versicolor
129 Iris-virginica 3 Iris-virginica
130 Iris-virginica 3 Iris-virginica
131 Iris-virginica 3 Iris-virginica
132 Iris-virginica 3 Iris-virginica
133 Iris-virginica 0 Iris-versicolor
134 Iris-virginica 0 Iris-versicolor
135 Iris-virginica 3 Iris-virginica
136 Iris-virginica 3 Iris-virginica
137 Iris-virginica 0 Iris-versicolor
138 Iris-virginica 0 Iris-versicolor
139 Iris-virginica 3 Iris-virginica
140 Iris-virginica 3 Iris-virginica
141 Iris-virginica 3 Iris-virginica
142 Iris-virginica 0 Iris-versicolor
143 Iris-virginica 3 Iris-virginica
144 Iris-virginica 3 Iris-virginica
145 Iris-virginica 3 Iris-virginica
146 Iris-virginica 0 Iris-versicolor
147 Iris-virginica 0 Iris-versicolor
148 Iris-virginica 3 Iris-virginica
149 Iris-virginica 0 Iris-versicolor
Kesimpulan :
K = 2
Inertia (SSE): 12.1437
Silhouette Score: 0.6295
Nilai skor inertia lebih besar dari yang lain dan nilai skor silhouette yang diperoleh adalah yang tertinggi dibandingkan dengan K lainnya (lebih mendekati 1).
K = 3
Inertia (SSE): 7.1386
Silhouette Score: 0.4825
Nilai skor inertia turun dan nilai skor silhouette juga mengalami penurunan dibandingkan dengan k=2 (menjauh dari 1).
K =4
Inertia (SSE): 5.5417
Silhouette Score: 0.4435
Nilai skor inertia dan nilai skor silhouette sama-sama mengalami penurunan (semakin jauh dari 1).
Maka berdasarkan hasil evaluasi yang telah dilakukan, nilai K = 2 merupakan jumlah klaster yang paling optimal. Hal ini ditunjukkan oleh nilai silhouette score paling mendekati 1 (0.6295).
Metode Elbow#
Metode Elbow untuk menentukan jumlah klaster 𝑘 yang optimal dengan memantau penurunan nilai inertia seiring bertambahnya 𝑘. Titik sebelum grafik melandai adalah titik siku (elbow point) → yaitu jumlah klaster optimal.
Contoh Elbow Method :
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
iris = pd.read_excel('data_iris.xlsx')
iris_x = iris.iloc[:, 1:5]
iris_x.head()
x_iris = np.array(iris_x)
scaler = MinMaxScaler()
x_scaled = scaler.fit_transform(x_iris)
x_scaled
wcss=[]
for i in range(1,11):
km = KMeans(i)
km.fit(iris_x)
wcss.append(km.inertia_)
np.array(wcss)
fig, ax = plt.subplots(figsize=(15,7))
ax = plt.plot(range(1,11),wcss, linewidth=2, color="red", marker ="8")
plt.axvline(x=3, ls='--')
plt.ylabel('WCSS')
plt.xlabel('No. of Clusters (k)')
plt.title('The Elbow Method', fontsize = 20)
plt.show()

Berdasarkan metode Elbow, jumlah klaster optimal adalah K = 3, karena pada titik ini terjadi penurunan WCSS (Within-Cluster Sum of Squares) yang signifikan sebelum grafik mulai melandai.
Fuzzy C-mean#
Konsep Fuzzy C-mean#
Fuzzy C-Means merupakan algoritma yang termasuk dalam kategori soft clustering, di mana setiap data dapat menjadi anggota dari lebih dari satu klaster secara bersamaan. Berbeda dengan hard clustering yang hanya menetapkan satu klaster untuk setiap data, Fuzzy C-Means menghitung derajat keanggotaan (membership value) dari setiap data terhadap seluruh klaster, dengan nilai antara 0 hingga 1. Penentuan klaster utama untuk suatu data dilakukan berdasarkan nilai derajat keanggotaan tertinggi. Pada tahap inisialisasi, jumlah total derajat keanggotaan dari satu data terhadap seluruh klaster adalah 1, yang mencerminkan distribusi keanggotaannya di semua klaster.
Langkah-langkah#
Tentukan jumlah klaster \(C\), nilai fuzzifier \(m\), dan inisialisasi nilai derajat keanggotaan awal secara acak dimana jumlah semua nilai keanggotaan untuk satu baris data terhadap seluruh klaster harus sama dengan 1.
Hitung pusat setiap klaster
Rumus :
$\(v_i = \frac{\sum_{k=1}^{n} u_{ik}^m x_k}{\sum_{k=1}^{n} u_{ik}^m}\)$Penjelasan :
\(v_{i}\) : pusat klaster ke-i (centroid).
\(u_{ik}\) : derajat keanggotaan data ke-k terhadap klaster ke-i.
\(m\) : nilai fuzzifier.
\(x_{k}\) : data ke-k.
\(n\) : jumlah total data.
Hitung jarak titik setiap data dari centroid menggunakan rumus Euclidian distance karena dibutuhkan untuk perhitungan update derajat keanggotaan.
Rumus :
$\(d(A, B) = \sqrt{ \sum_{i=1}^{n} (x_i - y_i)^2 }\)$Penjelasan :
\(d(A,B)\) : jarak antara vektor \(A\) dan \(B\). \(x_{i}, y_{i}\) : komponen ke-\(i\) dari masing-masing vektor.
\(n\) : jumlah total data.
Update derajat keanggotaan
Rumus :
$\(u_{ik} = \frac{1}{\sum_{j=1}^{c} \left( \frac{\lVert x_k - v_i \rVert}{\lVert x_k - v_j \rVert} \right)^{\frac{2}{m-1}}} \)$Penjelasan :
\(u_{ik}\) : derajat keanggotaan data ke-k terhadap klaster ke-i.
\(x_{k}\) : data ke-k.
\(v_{i},v_{j}\) : pusat klaster ke-i dan ke-j
\(||.||\) : jarak Euclidean antara titik dan pusat klaster.
\(m\) : nilai fuzzifier.
\(c\) : jumlah klaster.Jika \(m\) = 2, maka pangkatnya bisa menjadi 2.
Misalnya hitung \(u_{11}\), artinya hitung derajat keanggotaan data ke 1 pada klaster 1.
Ulangi langkah 2 hingga 4 secara iteratif hingga mencapai kondisi konvergen, yaitu ketika perubahan yang terjadi pada nilai pusat klaster atau derajat keanggotaan antar iterasi sangat kecil atau tidak signifikan lagi. Pada titik ini, proses klasterisasi dianggap telah mencapai hasil yang optimal.
Cek Konvergensi dengan fungsi objektif dengan membandingkan nilai fungsi objektif pada dua iterasi berurutan.
Rumus :
$\(J_m = \sum_{k=1}^{n} \sum_{i=1}^{c} u_{ik}^m \cdot \|x_k - v_i\|^2\)$Penjelasan :
\(u_{ik}\) : derajat keanggotaan data ke-k terhadap klaster ke-i.
\(m\) : nilai fuzzifier.
\(x_{k}\) : data ke-k.
\(v_{i}\) : pusat klaster ke-i (centroid).
\(||x_{k}-v_{i}||\): jarak (umumnya menggunakan euclidean distance)Jika selisih dari dua iterasi berturut-turut lebih kecil dari batas toleransi misalnya 0,00001, maka dianggap sudah konvergen dan iterasi berhenti.
Menentukan klaster terakhir setelah proses iterasi selesai (konvergen), maka selanjutnya mengklasifikasi setiap data pada suatu klaster dengan cara: menentukan kluster dengan nilai \(u_{ij}\) tertinggi untuk data tersebut. Misalnya untuk data \(x_{i}\) diperoleh derajat keanggotaan :
\(u_{11}\) = 0,2
\(u_{21}\) = 0,7
\(u_{31}\) = 0,1
Maka kluster utama untuk \(x_{1}\) adalah kluster ke-2, karena \(u_{21}\) adalah yang terbesar.
Komputasi Fuzzy C-mean#
m = 2
maksimal iterasi = 100
epsilon (batas toleransi) = 0,00001
import numpy as np
# Data xi
X = np.array([
[1, 2],
[2, 3],
[3, 4],
[6, 7],
[7, 8]
])
# Matriks keanggotaan awal U (acak)
U = np.array([
[0.5, 0.5],
[0.7, 0.3],
[0.8, 0.2],
[0.7, 0.3],
[0.6, 0.4]
])
# Parameter
m = 2 # Fuzziness
max_iter = 100 # Maksimum iterasi
epsilon = 1e-5 # Toleransi konvergensi 0.00001
def calculate_centroids(U, X, m):
um = U ** m
return (um.T @ X) / np.sum(um.T, axis=1)[:, None]
def update_membership(X, centroids, m):
n, c = X.shape[0], centroids.shape[0]
U_new = np.zeros((n, c))
for i in range(n):
for j in range(c):
num = np.linalg.norm(X[i] - centroids[j])
denom = sum((num / np.linalg.norm(X[i] - centroids[k])) ** (2/(m-1))
for k in range(c))
U_new[i, j] = 1 / denom
return U_new
def calculate_objective_function(U, X, centroids, m):
return sum((U[i,j]**m) * np.linalg.norm(X[i] - centroids[j])**2
for i in range(X.shape[0])
for j in range(centroids.shape[0]))
# Iterasi Fuzzy C-Means dengan detail output
prev_obj = None
for iteration in range(1, max_iter+1):
centroids = calculate_centroids(U, X, m)
U = update_membership(X, centroids, m)
obj = calculate_objective_function(U, X, centroids, m)
# Cetak detail iterasi
print(f"--- Iterasi {iteration} ---")
print("Centroids:")
print(np.round(centroids, 4))
print("Objektif J_m:", round(obj, 6))
print("Keanggotaan U:")
print(np.round(U, 4))
print()
# Cek konvergensi
if prev_obj is not None and abs(obj - prev_obj) < epsilon:
print(f"Konvergen pada iterasi ke-{iteration} (ΔJ = {abs(obj - prev_obj):.6f} < {epsilon})")
break
prev_obj = obj
else:
print("Maksimum iterasi tercapai tanpa konvergensi.")
# Hasil akhir (jika belum tercetak oleh break)
if abs(obj - prev_obj) >= epsilon:
print("\n=== Hasil Akhir ===")
print("Centroids Akhir:")
print(np.round(centroids, 4))
print("Keanggotaan Akhir (U):")
print(np.round(U, 4))
print("Nilai Fungsi Objektif Akhir:", round(obj, 6))
--- Iterasi 1 ---
Centroids:
[[3.861 4.861 ]
[3.5079 4.5079]]
Objektif J_m: 26.410066
Keanggotaan U:
[[0.4345 0.5655]
[0.3963 0.6037]
[0.2582 0.7418]
[0.5758 0.4242]
[0.5531 0.4469]]
--- Iterasi 2 ---
Centroids:
[[4.6034 5.6034]
[3.2074 4.2074]]
Objektif J_m: 20.900504
Keanggotaan U:
[[0.2729 0.7271]
[0.177 0.823 ]
[0.0165 0.9835]
[0.7999 0.2001]
[0.7146 0.2854]]
--- Iterasi 3 ---
Centroids:
[[6.0097 7.0097]
[2.4384 3.4384]]
Objektif J_m: 6.68533
Keanggotaan U:
[[0.0762 0.9238]
[0.0118 0.9882]
[0.0337 0.9663]
[1. 0. ]
[0.955 0.045 ]]
--- Iterasi 4 ---
Centroids:
[[6.4581 7.4581]
[2.0327 3.0327]]
Objektif J_m: 4.791511
Keanggotaan U:
[[3.460e-02 9.654e-01]
[1.000e-04 9.999e-01]
[7.260e-02 9.274e-01]
[9.868e-01 1.320e-02]
[9.882e-01 1.180e-02]]
--- Iterasi 5 ---
Centroids:
[[6.4879 7.4879]
[1.9747 2.9747]]
Objektif J_m: 4.766811
Keanggotaan U:
[[0.0306 0.9694]
[0. 1. ]
[0.0795 0.9205]
[0.9855 0.0145]
[0.9897 0.0103]]
--- Iterasi 6 ---
Centroids:
[[6.4882 7.4882]
[1.9673 2.9673]]
Objektif J_m: 4.766461
Keanggotaan U:
[[3.010e-02 9.699e-01]
[1.000e-04 9.999e-01]
[8.060e-02 9.194e-01]
[9.856e-01 1.440e-02]
[9.898e-01 1.020e-02]]
--- Iterasi 7 ---
Centroids:
[[6.488 7.488 ]
[1.9663 2.9663]]
Objektif J_m: 4.766454
Keanggotaan U:
[[3.010e-02 9.699e-01]
[1.000e-04 9.999e-01]
[8.070e-02 9.193e-01]
[9.856e-01 1.440e-02]
[9.898e-01 1.020e-02]]
Konvergen pada iterasi ke-7 (ΔJ = 0.000007 < 1e-05)
Link perhitungan manual hanya sampai dua iterasi :
https://docs.google.com/spreadsheets/d/1wLilhPFjf0tFwQjRFbflKhPWY88ZvvkZ3B9bXPkLoxw/edit?usp=sharing
Implementasi data iris 3 klaster#
n_cluster = 3
m = 2
epsilon = 0,00001
maksimal iterasi = 150
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from fcmeans import FCM
from sklearn.metrics import silhouette_score, accuracy_score, confusion_matrix
from scipy.spatial.distance import cdist
# 1. Baca dan siapkan data
df = pd.read_excel("class.xlsx")
df['id'] = df.index + 1
X = df[['petal_length', 'petal_width', 'sepal_length', 'sepal_width']].values
# 2. Normalisasi Min–Max
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
# 3. Fuzzy C-Means clustering
n_clusters = 3
m = 2
epsilon = 1e-5
fcm = FCM(n_clusters=n_clusters, m=m, error=epsilon, max_iter=150, random_state=42)
fcm.fit(X_scaled)
# 4. Hasil prediksi
labels = fcm.predict(X_scaled)
U = fcm.u
centers = fcm.centers
df['cluster'] = labels
# 5. Silhouette Score
sil_score = silhouette_score(X_scaled, labels)
print(f"Silhouette Score: {sil_score:.4f}")
# 6. Inertia (dengan label keras)
inertia = np.sum((X_scaled - centers[labels])**2)
print(f"Inertia (crisp): {inertia:.4f}")
# 7. Fungsi Objektif J_m
dist_matrix = cdist(X_scaled, centers, metric='euclidean')
Jm = np.sum((U**m) * (dist_matrix**2))
print(f"FCM Objective J_m: {Jm:.4f}")
# 8. Gabungkan hasil ke DataFrame
result_df = pd.DataFrame({
'id': df['id'],
'cluster': df['cluster'] # ← Tambahkan ini
})
for j in range(n_clusters):
result_df[f'membership_cluster_{j}'] = np.round(U[:, j], 4)
print(f"\n--- Hasil Clustering (epsilon: {epsilon}) ---")
print(result_df.to_string(index=False))
# 9. Mapping cluster ke class mayoritas
mapping = (
df.groupby('cluster')['class']
.agg(lambda x: x.mode()[0])
.to_dict()
)
df['predicted_class'] = df['cluster'].map(mapping)
# 10. Evaluasi
y_true = df['class']
y_pred = df['predicted_class']
classes = sorted(df['class'].unique())
cm = confusion_matrix(y_true, y_pred, labels=classes)
# Akurasi keseluruhan
acc = accuracy_score(y_true, y_pred)
print(f"\nAkurasi keseluruhan clustering terhadap label asli: {acc:.4%}")
# Persentase error per kelas
error_per_class = {}
for i, c in enumerate(classes):
total = cm[i].sum()
correct = cm[i, i]
error = 1 - correct/total if total > 0 else 0
error_per_class[c] = error
print("\nPersentase kesalahan per kelas:")
for c, e in error_per_class.items():
print(f" - {c}: {e:.2%}")
# Distribusi cluster per kelas (insight)
dist = pd.crosstab(df['class'], df['cluster'],
rownames=['Class'], colnames=['Cluster'])
print("\nDistribusi cluster per kelas:")
print(dist)
# Simpan hasil lengkap ke Excel
df.to_excel("hasil_fuzzy.xlsx", index=False)
# Tampilkan perbandingan class vs cluster vs predicted_class
pd.set_option('display.max_rows', None)
print("\nPerbandingan lengkap:")
print(df[['class', 'cluster', 'predicted_class']])
Silhouette Score: 0.4955
Inertia (crisp): 7.0830
FCM Objective J_m: 5.2330
--- Hasil Clustering (epsilon: 1e-05) ---
id cluster membership_cluster_0 membership_cluster_1 membership_cluster_2
1 0 0.9930 0.0023 0.0048
2 0 0.9313 0.0204 0.0483
3 0 0.9660 0.0105 0.0235
4 0 0.9371 0.0191 0.0439
5 0 0.9839 0.0053 0.0108
6 0 0.8700 0.0450 0.0850
7 0 0.9711 0.0091 0.0198
8 0 0.9989 0.0003 0.0008
9 0 0.8635 0.0413 0.0952
10 0 0.9534 0.0141 0.0325
11 0 0.9390 0.0205 0.0405
12 0 0.9907 0.0029 0.0064
13 0 0.9251 0.0227 0.0522
14 0 0.8778 0.0387 0.0835
15 0 0.8158 0.0680 0.1162
16 0 0.7127 0.1135 0.1738
17 0 0.8806 0.0420 0.0775
18 0 0.9927 0.0023 0.0050
19 0 0.8550 0.0499 0.0951
20 0 0.9397 0.0205 0.0398
21 0 0.9636 0.0113 0.0251
22 0 0.9531 0.0155 0.0315
23 0 0.9529 0.0159 0.0312
24 0 0.9548 0.0131 0.0321
25 0 0.9791 0.0064 0.0145
26 0 0.9278 0.0210 0.0512
27 0 0.9884 0.0035 0.0081
28 0 0.9878 0.0039 0.0083
29 0 0.9911 0.0028 0.0061
30 0 0.9651 0.0106 0.0243
31 0 0.9523 0.0142 0.0335
32 0 0.9550 0.0138 0.0312
33 0 0.8579 0.0520 0.0901
34 0 0.8063 0.0729 0.1208
35 0 0.9534 0.0141 0.0325
36 0 0.9771 0.0071 0.0158
37 0 0.9493 0.0166 0.0342
38 0 0.9534 0.0141 0.0325
39 0 0.8913 0.0334 0.0753
40 0 0.9971 0.0009 0.0020
41 0 0.9928 0.0023 0.0049
42 0 0.6619 0.0997 0.2384
43 0 0.9297 0.0221 0.0482
44 0 0.9349 0.0199 0.0451
45 0 0.9129 0.0289 0.0582
46 0 0.9237 0.0224 0.0539
47 0 0.9408 0.0202 0.0391
48 0 0.9565 0.0135 0.0300
49 0 0.9508 0.0165 0.0327
50 0 0.9939 0.0019 0.0042
51 1 0.0659 0.5350 0.3990
52 2 0.0521 0.3677 0.5802
53 1 0.0453 0.6034 0.3513
54 2 0.0669 0.1041 0.8290
55 2 0.0321 0.2643 0.7036
56 2 0.0079 0.0193 0.9728
57 2 0.0519 0.4727 0.4753
58 2 0.2488 0.1352 0.6160
59 2 0.0472 0.2573 0.6955
60 2 0.0704 0.0951 0.8345
61 2 0.2198 0.1644 0.6158
62 2 0.0238 0.0843 0.8919
63 2 0.0996 0.1397 0.7607
64 2 0.0166 0.0841 0.8992
65 2 0.0598 0.0744 0.8658
66 2 0.0599 0.3774 0.5627
67 2 0.0311 0.0981 0.8708
68 2 0.0542 0.0675 0.8783
69 2 0.0525 0.1986 0.7489
70 2 0.0639 0.0753 0.8608
71 2 0.0474 0.4434 0.5092
72 2 0.0160 0.0401 0.9439
73 2 0.0313 0.2043 0.7644
74 2 0.0202 0.0646 0.9152
75 2 0.0362 0.1413 0.8225
76 2 0.0493 0.3004 0.6502
77 2 0.0474 0.3981 0.5544
78 1 0.0237 0.7364 0.2399
79 2 0.0131 0.0648 0.9221
80 2 0.1103 0.0922 0.7975
81 2 0.0898 0.0963 0.8139
82 2 0.1196 0.1063 0.7740
83 2 0.0236 0.0365 0.9399
84 2 0.0246 0.1982 0.7772
85 2 0.0472 0.1203 0.8325
86 2 0.0738 0.3699 0.5563
87 1 0.0462 0.4997 0.4540
88 2 0.0501 0.1543 0.7956
89 2 0.0403 0.0685 0.8911
90 2 0.0418 0.0654 0.8928
91 2 0.0331 0.0550 0.9119
92 2 0.0243 0.1155 0.8601
93 2 0.0232 0.0385 0.9382
94 2 0.2311 0.1384 0.6306
95 2 0.0139 0.0261 0.9600
96 2 0.0406 0.0669 0.8925
97 2 0.0161 0.0326 0.9513
98 2 0.0217 0.0729 0.9054
99 2 0.2323 0.1272 0.6405
100 2 0.0109 0.0209 0.9681
101 1 0.0338 0.8200 0.1462
102 2 0.0389 0.3788 0.5824
103 1 0.0088 0.9449 0.0463
104 1 0.0208 0.7458 0.2334
105 1 0.0071 0.9480 0.0448
106 1 0.0380 0.8123 0.1497
107 2 0.0945 0.1962 0.7093
108 1 0.0293 0.8230 0.1477
109 1 0.0343 0.6766 0.2892
110 1 0.0473 0.7988 0.1539
111 1 0.0122 0.9007 0.0871
112 1 0.0233 0.7048 0.2719
113 1 0.0011 0.9916 0.0073
114 2 0.0509 0.3674 0.5817
115 1 0.0516 0.6175 0.3309
116 1 0.0173 0.8861 0.0966
117 1 0.0127 0.8654 0.1219
118 1 0.0737 0.7220 0.2043
119 1 0.0556 0.7361 0.2083
120 2 0.0518 0.2129 0.7353
121 1 0.0105 0.9399 0.0496
122 2 0.0499 0.3806 0.5696
123 1 0.0473 0.7645 0.1882
124 2 0.0291 0.4611 0.5098
125 1 0.0080 0.9502 0.0419
126 1 0.0225 0.8682 0.1094
127 2 0.0286 0.4177 0.5537
128 1 0.0312 0.4870 0.4818
129 1 0.0142 0.8710 0.1148
130 1 0.0331 0.7768 0.1900
131 1 0.0296 0.8226 0.1478
132 1 0.0809 0.7004 0.2187
133 1 0.0157 0.8697 0.1146
134 2 0.0282 0.2777 0.6942
135 2 0.0401 0.2616 0.6982
136 1 0.0384 0.8156 0.1459
137 1 0.0328 0.8213 0.1459
138 1 0.0160 0.8375 0.1465
139 2 0.0341 0.4040 0.5619
140 1 0.0027 0.9817 0.0156
141 1 0.0133 0.9203 0.0664
142 1 0.0130 0.9196 0.0674
143 2 0.0389 0.3788 0.5824
144 1 0.0108 0.9373 0.0518
145 1 0.0249 0.8698 0.1053
146 1 0.0106 0.9271 0.0622
147 1 0.0367 0.4890 0.4743
148 1 0.0077 0.9260 0.0663
149 1 0.0342 0.8014 0.1645
150 2 0.0358 0.4381 0.5261
Akurasi keseluruhan clustering terhadap label asli: 89.3333%
Persentase kesalahan per kelas:
- Iris-setosa: 0.00%
- Iris-versicolor: 8.00%
- Iris-virginica: 24.00%
Distribusi cluster per kelas:
Cluster 0 1 2
Class
Iris-setosa 50 0 0
Iris-versicolor 0 4 46
Iris-virginica 0 38 12
Perbandingan lengkap:
class cluster predicted_class
0 Iris-setosa 0 Iris-setosa
1 Iris-setosa 0 Iris-setosa
2 Iris-setosa 0 Iris-setosa
3 Iris-setosa 0 Iris-setosa
4 Iris-setosa 0 Iris-setosa
5 Iris-setosa 0 Iris-setosa
6 Iris-setosa 0 Iris-setosa
7 Iris-setosa 0 Iris-setosa
8 Iris-setosa 0 Iris-setosa
9 Iris-setosa 0 Iris-setosa
10 Iris-setosa 0 Iris-setosa
11 Iris-setosa 0 Iris-setosa
12 Iris-setosa 0 Iris-setosa
13 Iris-setosa 0 Iris-setosa
14 Iris-setosa 0 Iris-setosa
15 Iris-setosa 0 Iris-setosa
16 Iris-setosa 0 Iris-setosa
17 Iris-setosa 0 Iris-setosa
18 Iris-setosa 0 Iris-setosa
19 Iris-setosa 0 Iris-setosa
20 Iris-setosa 0 Iris-setosa
21 Iris-setosa 0 Iris-setosa
22 Iris-setosa 0 Iris-setosa
23 Iris-setosa 0 Iris-setosa
24 Iris-setosa 0 Iris-setosa
25 Iris-setosa 0 Iris-setosa
26 Iris-setosa 0 Iris-setosa
27 Iris-setosa 0 Iris-setosa
28 Iris-setosa 0 Iris-setosa
29 Iris-setosa 0 Iris-setosa
30 Iris-setosa 0 Iris-setosa
31 Iris-setosa 0 Iris-setosa
32 Iris-setosa 0 Iris-setosa
33 Iris-setosa 0 Iris-setosa
34 Iris-setosa 0 Iris-setosa
35 Iris-setosa 0 Iris-setosa
36 Iris-setosa 0 Iris-setosa
37 Iris-setosa 0 Iris-setosa
38 Iris-setosa 0 Iris-setosa
39 Iris-setosa 0 Iris-setosa
40 Iris-setosa 0 Iris-setosa
41 Iris-setosa 0 Iris-setosa
42 Iris-setosa 0 Iris-setosa
43 Iris-setosa 0 Iris-setosa
44 Iris-setosa 0 Iris-setosa
45 Iris-setosa 0 Iris-setosa
46 Iris-setosa 0 Iris-setosa
47 Iris-setosa 0 Iris-setosa
48 Iris-setosa 0 Iris-setosa
49 Iris-setosa 0 Iris-setosa
50 Iris-versicolor 1 Iris-virginica
51 Iris-versicolor 2 Iris-versicolor
52 Iris-versicolor 1 Iris-virginica
53 Iris-versicolor 2 Iris-versicolor
54 Iris-versicolor 2 Iris-versicolor
55 Iris-versicolor 2 Iris-versicolor
56 Iris-versicolor 2 Iris-versicolor
57 Iris-versicolor 2 Iris-versicolor
58 Iris-versicolor 2 Iris-versicolor
59 Iris-versicolor 2 Iris-versicolor
60 Iris-versicolor 2 Iris-versicolor
61 Iris-versicolor 2 Iris-versicolor
62 Iris-versicolor 2 Iris-versicolor
63 Iris-versicolor 2 Iris-versicolor
64 Iris-versicolor 2 Iris-versicolor
65 Iris-versicolor 2 Iris-versicolor
66 Iris-versicolor 2 Iris-versicolor
67 Iris-versicolor 2 Iris-versicolor
68 Iris-versicolor 2 Iris-versicolor
69 Iris-versicolor 2 Iris-versicolor
70 Iris-versicolor 2 Iris-versicolor
71 Iris-versicolor 2 Iris-versicolor
72 Iris-versicolor 2 Iris-versicolor
73 Iris-versicolor 2 Iris-versicolor
74 Iris-versicolor 2 Iris-versicolor
75 Iris-versicolor 2 Iris-versicolor
76 Iris-versicolor 2 Iris-versicolor
77 Iris-versicolor 1 Iris-virginica
78 Iris-versicolor 2 Iris-versicolor
79 Iris-versicolor 2 Iris-versicolor
80 Iris-versicolor 2 Iris-versicolor
81 Iris-versicolor 2 Iris-versicolor
82 Iris-versicolor 2 Iris-versicolor
83 Iris-versicolor 2 Iris-versicolor
84 Iris-versicolor 2 Iris-versicolor
85 Iris-versicolor 2 Iris-versicolor
86 Iris-versicolor 1 Iris-virginica
87 Iris-versicolor 2 Iris-versicolor
88 Iris-versicolor 2 Iris-versicolor
89 Iris-versicolor 2 Iris-versicolor
90 Iris-versicolor 2 Iris-versicolor
91 Iris-versicolor 2 Iris-versicolor
92 Iris-versicolor 2 Iris-versicolor
93 Iris-versicolor 2 Iris-versicolor
94 Iris-versicolor 2 Iris-versicolor
95 Iris-versicolor 2 Iris-versicolor
96 Iris-versicolor 2 Iris-versicolor
97 Iris-versicolor 2 Iris-versicolor
98 Iris-versicolor 2 Iris-versicolor
99 Iris-versicolor 2 Iris-versicolor
100 Iris-virginica 1 Iris-virginica
101 Iris-virginica 2 Iris-versicolor
102 Iris-virginica 1 Iris-virginica
103 Iris-virginica 1 Iris-virginica
104 Iris-virginica 1 Iris-virginica
105 Iris-virginica 1 Iris-virginica
106 Iris-virginica 2 Iris-versicolor
107 Iris-virginica 1 Iris-virginica
108 Iris-virginica 1 Iris-virginica
109 Iris-virginica 1 Iris-virginica
110 Iris-virginica 1 Iris-virginica
111 Iris-virginica 1 Iris-virginica
112 Iris-virginica 1 Iris-virginica
113 Iris-virginica 2 Iris-versicolor
114 Iris-virginica 1 Iris-virginica
115 Iris-virginica 1 Iris-virginica
116 Iris-virginica 1 Iris-virginica
117 Iris-virginica 1 Iris-virginica
118 Iris-virginica 1 Iris-virginica
119 Iris-virginica 2 Iris-versicolor
120 Iris-virginica 1 Iris-virginica
121 Iris-virginica 2 Iris-versicolor
122 Iris-virginica 1 Iris-virginica
123 Iris-virginica 2 Iris-versicolor
124 Iris-virginica 1 Iris-virginica
125 Iris-virginica 1 Iris-virginica
126 Iris-virginica 2 Iris-versicolor
127 Iris-virginica 1 Iris-virginica
128 Iris-virginica 1 Iris-virginica
129 Iris-virginica 1 Iris-virginica
130 Iris-virginica 1 Iris-virginica
131 Iris-virginica 1 Iris-virginica
132 Iris-virginica 1 Iris-virginica
133 Iris-virginica 2 Iris-versicolor
134 Iris-virginica 2 Iris-versicolor
135 Iris-virginica 1 Iris-virginica
136 Iris-virginica 1 Iris-virginica
137 Iris-virginica 1 Iris-virginica
138 Iris-virginica 2 Iris-versicolor
139 Iris-virginica 1 Iris-virginica
140 Iris-virginica 1 Iris-virginica
141 Iris-virginica 1 Iris-virginica
142 Iris-virginica 2 Iris-versicolor
143 Iris-virginica 1 Iris-virginica
144 Iris-virginica 1 Iris-virginica
145 Iris-virginica 1 Iris-virginica
146 Iris-virginica 1 Iris-virginica
147 Iris-virginica 1 Iris-virginica
148 Iris-virginica 1 Iris-virginica
149 Iris-virginica 2 Iris-versicolor