Kmeans聚類模型


模型介紹

對於有監督的數據挖掘算法而言,數據集中需要包括標簽變量(即因變量y的值)。
但在有些場景下並沒有給定的y值。對於這類數據的建模,一般稱為無監督的數據挖掘算法。
最為典型的當屬聚類算法。
Kmeans聚類算法利用距離遠近的思想將目標數據聚為指定的K個簇,
進而使樣本呈現簇內差異小,簇間差異大的特點。

聚類步驟

  • 從數據中隨機挑選k個樣本點作為原始的簇中⼼
  • 計算剩余樣本與簇中⼼的距離,並把各樣本標記為離k個簇中⼼最近的類別
  • 重新計算各簇中樣本點的均值,並以均值作為新的k個簇中⼼
  • 不斷重復第⼆步和第三步,直到簇中⼼的變化趨於穩定,形成最終的k個簇

K值的選擇——拐點法

簇內離差平方和拐點法的思想很簡單,就是在不同的K值下計算簇內的離差平方和,

然后通過可視化的方法找到“拐點”所對應的K值。當折線圖中的斜率由大突然變小,

並且之后的斜率變化緩慢,則認為突然變化的點就是尋找的目標點。

因為繼續隨着簇數K的增加,聚類效果不再有大的變化。

def k_SSE(X, clusters):
    # 選擇連續的K種不同的值
    K = range(1,clusters+1)
    # 構建空列表⽤於存儲總的簇內離差平⽅和
    TSSE = []
    for k in K:
        # ⽤於存儲各個簇內離差平⽅和
        SSE = []
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        # 返回簇標簽
        labels = kmeans.labels_
        # 返回簇中⼼
        centers = kmeans.cluster_centers_
        # 計算各簇樣本的離差平⽅和,並保存到列表中
        for label in set(labels):
            SSE.append(np.sum((X.loc[labels == label,]-centers[label,:])**2))
        # 計算總的簇內離差平⽅和
        TSSE.append(np.sum(SSE))

K值的選擇——輪廓系數法

該方法綜合考慮了簇的密集型與分散性兩個信息,如果數據集被分割為理想的K個簇,

那么對應的簇內樣本會很密集,而簇間樣本會很分散。

但系數接近於-1時,說明樣本i分配的不合理,需要將其分配到其他簇。

但系數接近於-1時,說明樣本i落在了模糊地帶,即簇的邊界。

但系數近似1時,說明樣本i的分配是合理的。

# 構造⾃定義函數
def k_silhouette(X, clusters):
    K = range(2,clusters+1)
    # 構建空列表,⽤於存儲不同簇數下的輪廓系數
    S = []
    for k in K:
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        labels = kmeans.labels_
        # 調⽤⼦模塊metrics中的silhouette_score函數,計算輪廓系數
        S.append(metrics.silhouette_score(X, labels, metric='euclidean'))

函數介紹

KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001)

n_clusters:⽤於指定聚類的簇數
init:⽤於指定初始的簇中⼼設置⽅法,
    如果為'k-means++',則表示設置的初始簇中⼼之間相距較遠;
    如果為'random',則表示從數據集中隨機挑選k個樣本作為初始簇中⼼;
    如果為數組,則表示⽤戶指定具體的簇中⼼
n_init:⽤於指定Kmeans算法運⾏的次數,每次運⾏時都會選擇不同的初始簇中⼼,⽬的是防⽌算
    法收斂於局部最優,默認為10
max_iter:⽤於指定單次運⾏的迭代次數,默認為300
tol:⽤於指定算法收斂的閾值,默認為0.0001

K值選擇代碼演示

# 導入第三方包
import pandas as pd
import numpy as np  
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import metrics

# 隨機生成三組二元正態分布隨機數 
np.random.seed(1234)
mean1 = [0.5, 0.5]
cov1 = [[0.3, 0], [0, 0.3]]
x1, y1 = np.random.multivariate_normal(mean1, cov1, 1000).T
mean2 = [0, 8]
cov2 = [[1.5, 0], [0, 1]]
x2, y2 = np.random.multivariate_normal(mean2, cov2, 1000).T
mean3 = [8, 4]
cov3 = [[1.5, 0], [0, 1]]
x3, y3 = np.random.multivariate_normal(mean3, cov3, 1000).T

# 繪制三組數據的散點圖
plt.scatter(x1,y1)
plt.scatter(x2,y2)
plt.scatter(x3,y3)
# 顯示圖形
plt.show()


# !!!!!!!!!!!!!!!!!!!!!!!!!
# 構造自定義函數,用於繪制不同k值和對應總的簇內離差平方和的折線圖
def k_SSE(X, clusters):
    # 選擇連續的K種不同的值
    K = range(1,clusters+1)
    # 構建空列表用於存儲總的簇內離差平方和
    TSSE = []
    for k in K:
        # 用於存儲各個簇內離差平方和
        SSE = []
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        # 返回簇標簽
        labels = kmeans.labels_
        # 返回簇中心
        centers = kmeans.cluster_centers_
        # 計算各簇樣本的離差平方和,並保存到列表中
        for label in set(labels):
            SSE.append(np.sum((X.loc[labels == label,]-centers[label,:])**2))
        # 計算總的簇內離差平方和 
        TSSE.append(np.sum(SSE))

    # 中文和負號的正常顯示
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 設置繪圖風格
    plt.style.use('ggplot')
    # 繪制K的個數與GSSE的關系
    plt.plot(K, TSSE, 'b*-')
    plt.xlabel('簇的個數')
    plt.ylabel('簇內離差平方和之和')
    # 顯示圖形
    plt.show()

# 將三組數據集匯總到數據框中
X = pd.DataFrame(np.concatenate([np.array([x1,y1]),np.array([x2,y2]),np.array([x3,y3])], axis = 1).T)
# 自定義函數的調用
k_SSE(X, 15)


# !!!!!!!!!!!!!!!!!!!!!!!!!
# 構造自定義函數,用於繪制不同k值和對應輪廓系數的折線圖
def k_silhouette(X, clusters):
    K = range(2,clusters+1)
    # 構建空列表,用於存儲個中簇數下的輪廓系數
    S = []
    for k in K:
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        labels = kmeans.labels_
        # 調用字模塊metrics中的silhouette_score函數,計算輪廓系數
        S.append(metrics.silhouette_score(X, labels, metric='euclidean'))

    # 中文和負號的正常顯示
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 設置繪圖風格
    plt.style.use('ggplot')    
    # 繪制K的個數與輪廓系數的關系
    plt.plot(K, S, 'b*-')
    plt.xlabel('簇的個數')
    plt.ylabel('輪廓系數')
    # 顯示圖形
    plt.show()
    
# 自定義函數的調用
k_silhouette(X, 15)

模型代碼演示

# 讀取iris數據集
iris = pd.read_csv(r'iris.csv')
# 提取出用於建模的數據集X
X = iris.drop(labels = 'Species', axis = 1)
# 構建Kmeans模型
kmeans = KMeans(n_clusters = 3)
kmeans.fit(X)
# 聚類結果標簽
X['cluster'] = kmeans.labels_
# 各類頻數統計
X.cluster.value_counts()

# 導入第三方模塊
import seaborn as sns
# 三個簇的簇中心
centers = kmeans.cluster_centers_
# 繪制聚類效果的散點圖
sns.lmplot(x = 'Petal_Length', y = 'Petal_Width', hue = 'cluster', markers = ['^','s','o'], 
           data = X, fit_reg = False, scatter_kws = {'alpha':0.8}, legend_out = False)
plt.scatter(centers[:,2], centers[:,3], marker = '*', color = 'black', s = 130)
plt.xlabel('花瓣長度')
plt.ylabel('花瓣寬度')
# 圖形顯示
plt.show()

# 增加一個輔助列,將不同的花種映射到0,1,2三種值,目的方便后面圖形的對比
iris['Species_map'] = iris.Species.map({'virginica':0,'setosa':1,'versicolor':2})
# 繪制原始數據三個類別的散點圖
sns.lmplot(x = 'Petal_Length', y = 'Petal_Width', hue = 'Species_map', data = iris, markers = ['^','s','o'],
           fit_reg = False, scatter_kws = {'alpha':0.8}, legend_out = False)
plt.xlabel('花瓣長度')
plt.ylabel('花瓣寬度')
# 圖形顯示
plt.show()



# 讀取球員數據
players = pd.read_csv(r'players.csv')
# 繪制得分與命中率的散點圖
sns.lmplot(x = '得分', y = '命中率', data = players, 
           fit_reg = False, scatter_kws = {'alpha':0.8, 'color': 'steelblue'})
plt.show()

from sklearn import preprocessing
# 數據標准化處理
X = preprocessing.minmax_scale(players[['得分','罰球命中率','命中率','三分命中率']])
# 將數組轉換為數據框
X = pd.DataFrame(X, columns=['得分','罰球命中率','命中率','三分命中率'])
# 使用拐點法選擇最佳的K值
k_SSE(X, 15)

# 使用輪廓系數選擇最佳的K值
k_silhouette(X, 10)

# 將球員數據集聚為3類
kmeans = KMeans(n_clusters = 3)
kmeans.fit(X)
# 將聚類結果標簽插入到數據集players中
players['cluster'] = kmeans.labels_
# 構建空列表,用於存儲三個簇的簇中心
centers = []
for i in players.cluster.unique():
    centers.append(players.ix[players.cluster == i,['得分','罰球命中率','命中率','三分命中率']].mean())
# 將列表轉換為數組,便於后面的索引取數
centers = np.array(centers)

# 繪制散點圖
sns.lmplot(x = '得分', y = '命中率', hue = 'cluster', data = players, markers = ['^','s','o'],
           fit_reg = False, scatter_kws = {'alpha':0.8}, legend = False)
# 添加簇中心
plt.scatter(centers[:,0], centers[:,2], c='k', marker = '*', s = 180)
plt.xlabel('得分')
plt.ylabel('命中率')
# 圖形顯示
plt.show()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM