오늘은 주성분 분석과 군집화에 대한 내용을 배웠다. 주성분 분석이 엄청 복잡하지만 이후 작업을 할 때 매우 유용하게 사용할 수 있는 내용이라 어렵지만 최대한 이해하려고 들어서 대략적인 이미지는 그릴 수 있었다.
from scipy.stats import zscore
df.cov().round(3)

df_scaled = pd.DataFrame(data=zscore(a=df, ddof=1), columns=df.columns)

df_scaled.cov().round(3)

from sklearn.decomposition import PCA
model_pca = PCA()
pca_score = model_pca.fit_transform(X=df_scaled)
cols = ['PC' + str(i + 1) for i in range(df_scaled.shape[1])]
# ['PC1', 'PC2', 'PC3', 'PC4', 'PC5', 'PC6', 'PC7', 'PC8', 'PC9']
pca_score = pd.DataFrame(data=pca_score, columns=cols)
pca_score.head()

model_pca.explained_variance_
# array([2.66992336, 2.04667073, 1.61992396, 0.99566901, 0.64310064,
# 0.52622864, 0.37703769, 0.07052773, 0.05091824])
model_pca.explained_variance_.sum()
# np.float64(9.0)
model_pca.explained_variance_ratio_
# array([0.29665815, 0.22740786, 0.17999155, 0.11062989, 0.07145563,
# 0.05846985, 0.04189308, 0.00783641, 0.00565758])
model_pca.explained_variance_ratio_.cumsum()
# array([0.29665815, 0.52406601, 0.70405756, 0.81468745, 0.88614308,
# 0.94461293, 0.986506 , 0.99434242, 1. ])
eigenVectors = pd.DataFrame(
data=model_pca.components_.T,
index=df_scaled.columns,
columns=cols
)
eigenVectors

eigenVectors['PC1']
# calories -0.242918
# protein 0.401120
# fat 0.091637
# sodium -0.204797
# fiber 0.543754
# carbo -0.349896
# sugars -0.132769
# potass 0.520925
# vitamins -0.150561
# Name: PC1, dtype: float64
np.dot(a=eigenVectors['PC1'], b=df_scaled.iloc[0, :])
# np.float64(5.043540242255567)
hds.plot.screeplot(X=pca_score)

hds.plot.biplot(score=pca_score, coefs=eigenVectors, zoom=4)

from scipy.cluster.hierarchy import linkage
method : 판단 기준 설정single : 최단 연결법(기본값)complete : 최장 연결법average : 평균 연결법centroid : 중심 연결법ward : 와드 연결법optimal_ordering : 행렬 재정렬 → 시각화 결과 개선Falsehc = linkage(
y=df_scaled, method='single', metric='euclidean',
optimal_ordering=True
)
from scipy.cluster.hierarchy import dendrogram
orientation : 덴드로그램 출력 방향 지정labels : 관측값 인덱스 대신 출력할 라벨 목록 지정plt.figure(figsize=(12, 4))
dendrogram(Z=hc, orientation='top', labels=df.index)
plt.show()

def plot_dendrogram(y, method):
hc = linkage(
y=y, method=method, metric='euclidean',
optimal_ordering=True
)
plt.figure(figsize=(12, 4))
dendrogram(Z=hc, orientation='top', labels=df.index)
plt.show()
plot_dendrogram(y=df_scaled, method='complete')

plot_dendrogram(y=df_scaled, method='average')

plot_dendrogram(y=df_scaled, method='centroid')

plot_dendrogram(y=df_scaled, method='ward')

from sklearn.cluster import KMeans
n_clusters : 군집 수 k 지정init : 초기 중심정 생성 방법 지정‘k-means++’model = KMeans(n_clusters=8, init='k-means++', random_state=0)
model.fit(X=df_scaled)
cluster_labels = model.predict(X=df_scaled)
# array([4, 6, 4, 4, 0, 0, 0, 6, 5, 5, 0, 5, 0, 6, 0, 2, 2, 0, 0, 6, 3, 2,
# 0, 2, 0, 0, 3, 1, 1, 0, 0, 0, 5, 5, 6, 0, 0, 0, 7, 7, 2, 5, 0, 3,
# 6, 6, 6, 5, 0, 6, 5, 6, 1, 7, 3, 3, 5, 4, 1, 6, 3, 2, 2, 3, 3, 3,
# 0, 5, 3, 7, 1, 7, 2, 0, 5, 5, 0], dtype=int32)
pd.Series(data=cluster_labels).value_counts().sort_index()
# 0 22
# 1 5
# 2 8
# 3 10
# 4 4
# 5 12
# 6 11
# 7 5
# Name: count, dtype: int64
내부평가 : 군집 정보가 없을 때
외부평가 : 군집 정보가 있을 때
model.inertia_
# 215.61245219621284
hds.plot.wcss(X=df_scaled, k=10)

하나의 관측값 선택 → 가장 인접한 이웃 군집에 속한 개별 관측값과의 거리 평균 계산(a)
→ 같은 군집에 속한 관측값들과의 거리 평균 계산(b)
→ (a) - (b) 를 (a)로 나눈값 = 해당 관측값의 실루엣 계수
→ 모든 관측값에 대해 실루엣 계수 평균을 계산
from sklearn.metrics import silhouette_score
silhouette_score(X=df_scaled, labels=cluster_labels)
# 0.3075777347145458
hds.plot.silhouette(X=df_scaled, k=10)

model.set_params(n_clusters=6).fit(X=df_scaled)
df['k-means'] = model.predict(X=df_scaled)
silhouette_score(X=df_scaled, labels=df['k-means'])
# 0.2750794137284007
sns.scatterplot(
data=pca_score, x='PC1', y='PC2',
s=50, alpha=0.5,
hue=df['k-means'], palette='Set1'
)
plt.title(label='k-means with PCA', fontweight='bold')
plt.axvline(x=0, color='0.5', linewidth=0.5, linestyle='--')
plt.axhline(y=0, color='0.5', linewidth=0.5, linestyle='--')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), title='k-means')
plt.show()

from sklearn.manifold import TSNE
tsne = TSNE(n_components=2, perplexity=15, random_state=0)
X_tsne = tsne.fit_transform(X=df_scaled)
df_tsne = pd.DataFrame(data=X_tsne, columns=['tSNE1', 'tSNE2'])
sns.scatterplot(
data=df_tsne, x='tSNE1', y='tSNE2',
s=50, alpha=0.5,
hue=df['k-means'], palette='Set1'
)
plt.title(label='k-means with t-SNE(perplexity: 15)', fontweight='bold')
plt.axvline(x=0, color='0.5', linewidth=0.5, linestyle='--')
plt.axhline(y=0, color='0.5', linewidth=0.5, linestyle='--')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), title='k-means')
plt.show()

from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=2.0, min_samples=5)
df['dbscan'] = dbscan.fit_predict(X=df_scaled)
df['dbscan'].value_counts().sort_index()
# dbscan
# -1 22
# 0 50
# 1 5
# Name: count, dtype: int64
sns.scatterplot(
data=df_tsne, x='tSNE1', y='tSNE2',
s=50, alpha=0.5,
hue=df['dbscan'], palette='Set1'
)
plt.title(label='DBSCAN with t-SNE(perplexity: 15)', fontweight='bold')
plt.axvline(x=0, color='0.5', linewidth=0.5, linestyle='--')
plt.axhline(y=0, color='0.5', linewidth=0.5, linestyle='--')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), title='DBSCAN')
plt.show()

사람은 보통 3차원까지만 이미지를 그릴 수 있기 때문에 고차원 데이터를 다루는 내용이 많이 나오면 처음 큰 그림을 그리는 부분이 꽤나 힘든 것 같다.