K-Means 聚類別分析與階層式聚類別分析是機器學習中常用的非監督式學習方法,適用於將資料分群並探索資料結構。K-Means 需要預先指定叢集數量 K,而階層式聚類別則以樹狀圖呈現不同層次的叢集關係,不需事先設定叢集數。選擇 K 值對 K-Means 的效能影響顯著,肘部法則是常用的 K 值選取方法,藉由觀察不同 K 值對應的組內變異程度變化,找出斜率變化最大的「肘部」點,即為最佳 K 值。實務上,可透過視覺化不同叢集數量下的結果,輔以肘部法則選取 K 值,以獲得最佳的叢集效果。程式碼範例中,R 語言使用 kmeans 函式執行 K-Means,hclust 函式執行階層式聚類別,並以 ggplot2 繪製視覺化圖表;Python 則使用 KMeanslinkage 函式,並以 matplotlib 進行視覺化。兩種語言皆提供完整的工具,方便進行叢集分析與結果呈現。

K-Means聚類別分析與階層式聚類別分析

K-Means聚類別中心視覺化

K-Means聚類別分析是一種常見的無監督學習方法,用於將資料分為K個不同的群組。在進行K-Means聚類別後,我們可以透過視覺化聚類別中心來瞭解每個群組的特性。

R語言實作

centers <- as.data.frame(t(centers))
names(centers) <- paste("Cluster", 1:5)
centers$Symbol <- row.names(centers)
centers <- gather(centers, 'Cluster', 'Mean', -Symbol)
centers$Color = centers$Mean > 0
ggplot(centers, aes(x=Symbol, y=Mean, fill=Color)) +
  geom_bar(stat='identity', position='identity', width=.75) +
  facet_grid(Cluster ~ ., scales='free_y')

內容解密:

  1. 將聚類別中心轉置並轉換為資料框架,以便於後續處理。
  2. 使用gather函式將資料從寬格式轉換為長格式,方便視覺化。
  3. 根據Mean值的正負設定Color欄位,用於區分正負值。
  4. 使用ggplot2套件繪製分面條形圖,每個分面代表一個聚類別。

Python實作

centers = pd.DataFrame(kmeans.cluster_centers_, columns=syms)
f, axes = plt.subplots(5, 1, figsize=(5, 5), sharex=True)
for i, ax in enumerate(axes):
    center = centers.loc[i, :]
    maxPC = 1.01 * np.max(np.max(np.abs(center)))
    colors = ['C0' if l > 0 else 'C1' for l in center]
    ax.axhline(color='#888888')
    center.plot.bar(ax=ax, color=colors)
    ax.set_ylabel(f'Cluster {i + 1}')
    ax.set_ylim(-maxPC, maxPC)

內容解密:

  1. 將K-Means聚類別中心轉換為Pandas DataFrame。
  2. 使用subplots建立多個子圖,每個子圖代表一個聚類別。
  3. 根據每個聚類別中心的正負值設定不同的顏色。
  4. 繪製條形圖來展示每個變數在聚類別中的均值。

K-Means與階層式聚類別比較

K-Means聚類別和階層式聚類別都是無監督學習中常用的方法,但它們在應用場景和結果解釋上有所不同。K-Means需要預先指定聚類別數量,而階層式聚類別則透過樹狀結構展示不同層次的聚類別結果。

選擇最佳聚類別數量

在K-Means聚類別中,選擇合適的K值至關重要。常見的方法包括肘部法則(Elbow Method),即觀察不同K值下解釋變異的比例。

R語言實作肘部法則

pct_var <- data.frame(pct_var = 0, num_clusters = 2:14)
totalss <- kmeans(df, centers=14, nstart=50, iter.max=100)$totss
for (i in 2:14) {
  kmCluster <- kmeans(df, centers=i, nstart=50, iter.max=100)
  pct_var[i-1, 'pct_var'] <- kmCluster$betweenss / totalss
}

Python實作肘部法則

inertia = []
for n_clusters in range(2, 14):
    kmeans = KMeans(n_clusters=n_clusters, random_state=0).fit(top_sp)
    inertia.append(kmeans.inertia_ / n_clusters)
inertias = pd.DataFrame({'n_clusters': range(2, 14), 'inertia': inertia})
ax = inertias.plot(x='n_clusters', y='inertia')
plt.xlabel('Number of clusters(k)')
plt.ylabel('Average Within-Cluster Squared Distances')

內容解密:

  1. 計算不同K值下的解釋變異比例或平均內部平方距離。
  2. 繪製K值與解釋變異比例或平均內部平方距離的關係圖。
  3. 觀察圖形中的「肘部」位置,以確定最佳K值。

主要觀念與關鍵字彙

  • K-Means需要預先指定K值。
  • 聚類別中心視覺化有助於理解每個群組的特性。
  • 肘部法則是選擇最佳K值的常用方法。
  • 階層式聚類別提供了不同層次的聚類別結構。

階層式分群(Hierarchical Clustering)

階層式分群是一種無監督學習方法,用於根據資料點之間的相似性或距離將其分組。它透過建立樹狀結構(稱為樹狀圖)來呈現資料的層次關係。

距離度量(Dissimilarity Metric)

在數值資料的應用中,最重要的選擇是相異性度量。階層式分群首先將每個記錄設定為自己的群集,然後迭代合併最不相異的群集。

R 語言實作

在 R 中,可以使用 hclust 函式進行階層式分群。與 kmeans 的主要區別在於,hclust 操作的是成對距離 d_i, j 而不是資料本身。可以使用 dist 函式計算這些距離。例如,以下程式碼對一組公司的股票收益進行階層式分群:

syms1 <- c('GOOGL', 'AMZN', 'AAPL', 'MSFT', 'CSCO', 'INTC', 'CVX', 'XOM', 'SLB', 'COP', 'JPM', 'WFC', 'USB', 'AXP', 'WMT', 'TGT', 'HD', 'COST')
df <- t(sp500_px[row.names(sp500_px) >= '2011-01-01', syms1])
d <- dist(df)
hcl <- hclust(d)

#### 內容解密:
1. `syms1 <- c(...)`:定義要分析的股票程式碼列表。
2. `df <- t(sp500_px[row.names(sp500_px) >= '2011-01-01', syms1])`:提取自 201111 日以來的股票價格資料,並進行轉置,以便將股票放在行上。
3. `d <- dist(df)`:計算股票收益之間的距離。
4. `hcl <- hclust(d)`:對距離矩陣進行階層式分群。

#### Python 語言實作
在 Python 中,可以使用 `scipy.cluster.hierarchy` 模組中的 `linkage` 函式進行階層式分群。例如:

```python
syms1 = ['AAPL', 'AMZN', 'AXP', 'COP', 'COST', 'CSCO', 'CVX', 'GOOGL', 'HD', 'INTC', 'JPM', 'MSFT', 'SLB', 'TGT', 'USB', 'WFC', 'WMT', 'XOM']
df = sp500_px.loc[sp500_px.index >= '2011-01-01', syms1].transpose()
Z = linkage(df, method='complete')

#### 內容解密:
1. `syms1 = [...]`:定義要分析的股票程式碼列表。
2. `df = sp500_px.loc[sp500_px.index >= '2011-01-01', syms1].transpose()`:提取自 2011 年 1 月 1 日以來的股票價格資料,並進行轉置,以便將股票放在行上。
3. `Z = linkage(df, method='complete')`:對資料進行階層式分群,使用完全連結法。

### 樹狀圖(Dendrogram)
階層式分群可以自然地以樹狀圖的形式呈現。在 R 中,可以使用 `plot` 命令繪製樹狀圖。在 Python 中,可以使用 `dendrogram` 函式繪製樹狀圖。

```r
plot(hcl)
fig, ax = plt.subplots(figsize=(5, 5))
dendrogram(Z, labels=df.index, ax=ax, color_threshold=0)
plt.xticks(rotation=90)
ax.set_ylabel('distance')

#### 內容解密:
1. `fig, ax = plt.subplots(figsize=(5, 5))`:建立一個大小為 5x5 的圖形
2. `dendrogram(Z, labels=df.index, ax=ax, color_threshold=0)`:繪製樹狀圖使用 `Z` 中的連結資訊和 `df.index` 中的標籤
3. `plt.xticks(rotation=90)`:將 x 軸標籤旋轉 90
4. `ax.set_ylabel('distance')`:設定 y 軸標籤為距離」。

### 從階層式分群中提取群集
可以透過在樹狀圖中滑動水平線來識別不同的群集數量在 R 中可以使用 `cutree` 函式提取特定數量的群集在 Python 中可以使用 `fcluster` 函式提取特定數量的群集

```r
cutree(hcl, k=4)
memb = fcluster(Z, 4, criterion='maxclust')
memb = pd.Series(memb, index=df.index)
for key, item in memb.groupby(memb):
    print(f"{key} : {', '.join(item.index)}")

#### 內容解密:
1. `memb = fcluster(Z, 4, criterion='maxclust')`:`Z` 中的連結資訊中提取 4 個群集
2. `memb = pd.Series(memb, index=df.index)`:將群整合員資訊轉換為 Pandas Series使用 `df.index` 中的索引
3. `for key, item in memb.groupby(memb)`:按群整合員分組並列印每個群集的成員

### 相異性度量(Measures of Dissimilarity)
有四種常見的相異性度量方法完全連結法單一連結法平均連結法和最小變異數法這些方法都受到大多數階層式分群軟體的支援包括 `hclust``linkage`。

#### 不同相異性度量的比較
7-9 將四種相異性度量方法應用於 ExxonMobil 和 Chevron 股票收益的階層式分群對於每種方法都保留了四個群集

## 模型基礎的分群法(Model-Based Clustering)

傳統的分群方法如階層分群法Hierarchical Clustering和K-means主要依賴於直觀的距離測量並未涉及機率模型的假設近二十年來隨著統計理論的發展模型基礎的分群法逐漸受到重視該方法根據資料服從特定機率分佈的假設能夠更嚴謹地確定分群的數量和結構

### 多變數常態分佈(Multivariate Normal Distribution)

模型基礎的分群法通常根據多變數常態分佈的假設多變數常態分佈是單變數常態分佈在多維空間的推廣能夠描述多個變數之間的聯合分佈其數學表示式由均值向量 $\mu$ 和共變異數矩陣 $\Sigma$ 決定

$$
X_1, X_2, ..., X_p \sim N_p(\mu, \Sigma)
$$

共變異數矩陣 $\Sigma$ 描述了變數之間的相關性和各自的變異程度它是一個對稱矩陣其對角線元素代表各變數的變異數而非對角線元素則代表變數之間的共變異數

$$
\Sigma = 
\begin{bmatrix}
\sigma_1^2 & \sigma_{1,2} & \cdots & \sigma_{1,p} \\
\sigma_{2,1} & \sigma_2^2 & \cdots & \sigma_{2,p} \\
\vdots & \vdots & \ddots & \vdots \\
\sigma_{p,1} & \sigma_{p,2} & \cdots & \sigma_p^2
\end{bmatrix}
$$

#### 圖表說明
此圖示展示了兩個變數X和Y的多變數常態分佈機率輪廓均值分別為 $\mu_x = 0.5$$\mu_y = -0.5$,共變異數矩陣為
$$
\Sigma = 
\begin{bmatrix}
1 & 1 \\
1 & 2
\end{bmatrix}
$$
由於 $\sigma_{xy}$ 為正X和Y呈現正相關

```plantuml
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title KMeans 階層式聚類別分析與最佳叢集數量

package "資料視覺化流程" {
    package "資料準備" {
        component [資料載入] as load
        component [資料清洗] as clean
        component [資料轉換] as transform
    }

    package "圖表類型" {
        component [折線圖 Line] as line
        component [長條圖 Bar] as bar
        component [散佈圖 Scatter] as scatter
        component [熱力圖 Heatmap] as heatmap
    }

    package "美化輸出" {
        component [樣式設定] as style
        component [標籤註解] as label
        component [匯出儲存] as export
    }
}

load --> clean --> transform
transform --> line
transform --> bar
transform --> scatter
transform --> heatmap
line --> style --> export
bar --> label --> export

note right of scatter
  探索變數關係
  發現異常值
end note

@enduml

常態分佈混合模型(Mixtures of Normals)

模型基礎的分群法假設每個資料點來自於 $K$ 個不同的多變數常態分佈,其中 $K$ 是分群的數量。每個分佈具有不同的均值 $\mu_k$ 和共變異數矩陣 $\Sigma_k$。對於具有兩個變數 $X$ 和 $Y$ 的資料集,每個資料點 $(X_i, Y_i)$ 被視為來自於 $K$ 個多變數常態分佈之一:

$$ N(\mu_1, \Sigma_1), N(\mu_2, \Sigma_2), …, N(\mu_K, \Sigma_K) $$

內容解密:

  1. 多變數常態分佈的假設:模型基礎的分群法依賴於資料符合多變數常態分佈的假設,這使得分群結果能夠反映資料的機率結構。
  2. 共變異數矩陣的作用:共變異數矩陣描述了變數之間的相關性和各自的離散程度,對分群結果有重要影響。
  3. 常態分佈混合模型:透過將資料視為來自多個常態分佈的混合,能夠捕捉複雜的資料結構,並進行更精確的分群。

R語言與Python的實作

在R語言中,mclust 包提供了豐富的模型基礎分群功能。例如,對股票收益率資料進行分群:

library(mclust)
df <- sp500_px[row.names(sp500_px) >= '2011-01-01', c('XOM', 'CVX')]
mcl <- Mclust(df)
summary(mcl)

內容解密:

  1. mclust套件的使用:R語言中的mclust套件用於實作模型基礎的分群法,能夠自動確定最佳的分群數量和結構。
  2. Mclust函式的引數:透過調整Mclust函式的引數,可以控制分群模型的複雜度和擬合優度。
  3. summary函式的輸出summary函式提供了分群結果的詳細資訊,包括分群數量、各分群的引數估計等。

在Python中,sklearn.mixture.GaussianMixture 類別可用於模型基礎的分群:

from sklearn.mixture import GaussianMixture

df = sp500_px.loc[sp500_px.index >= '2011-01-01', ['XOM', 'CVX']]
mclust = GaussianMixture(n_components=2).fit(df)

內容解密:

  1. GaussianMixture類別的使用:Python中的GaussianMixture類別實作了根據高斯混合模型的分群,能夠處理多維資料。
  2. n_components引數的選擇:需要根據資料特徵選擇適當的 $K$ 值,以獲得最佳的分群效果。
  3. fit方法的應用:透過fit方法,可以將高斯混合模型擬合到資料上,並獲得分群結果。

分群結果的視覺化

無論是在R還是在Python中,分群結果都能夠透過視覺化來展示。例如,在R中使用 ggplot2 套件:

cluster <- factor(predict(mcl)$classification)
ggplot(data=df, aes(x=XOM, y=CVX, color=cluster, shape=cluster)) +
  geom_point(alpha=.8)

內容解密:

  1. ggplot2套件的使用:R語言中的ggplot2套件提供了強大的資料視覺化功能,能夠清晰地展示分群結果。
  2. predict函式的作用:透過predict函式,可以獲得每個資料點所屬的分群標籤。
  3. geom_point圖層的應用:使用geom_point圖層,可以將分群結果以散點圖的形式展示出來。

在Python中,可以使用 matplotlib

fig, ax = plt.subplots(figsize=(4, 4))
colors = [f'C{c}' for c in mclust.predict(df)]
df.plot.scatter(x='XOM', y='CVX', c=colors, alpha=0.5, ax=ax)
ax.set_xlim(-3, 3)
ax.set_ylim(-3, 3)

內容解密:

  1. matplotlib的使用:Python中的matplotlib函式庫提供了豐富的視覺化功能,能夠靈活地展示分群結果。
  2. predict方法的應用:透過predict方法,可以獲得每個資料點所屬的分群標籤,並用於視覺化。
  3. scatter圖的繪製:使用scatter圖,可以直觀地展示不同分群之間的差異。