模型介紹
對於有監督的數據挖掘算法而言,數據集中需要包括標簽變量(即因變量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()
