利用Kmeans聚類(lèi)分析兩類(lèi)問(wèn)題

聚類(lèi)分析是一種無(wú)監(jiān)督的學(xué)習(xí)方法,根據(jù)一定條件將相對(duì)同質(zhì)的樣本歸到一個(gè)類(lèi)總(俗話(huà)說(shuō)人以類(lèi)聚,物以群分)
正式一點(diǎn)的:聚類(lèi)是對(duì)點(diǎn)集進(jìn)行考察并按照某種距離測(cè)度將他們聚成多個(gè)“簇”的過(guò)程。聚類(lèi)的目標(biāo)是使得同一簇內(nèi)的點(diǎn)之間的距離較短,而不同簇中點(diǎn)之間的距離較大。

兩種方法對(duì)比:

在K-means聚類(lèi)中,是預(yù)先規(guī)定出要產(chǎn)生多少個(gè)類(lèi)別的數(shù)量,再根據(jù)類(lèi)別數(shù)量自動(dòng)聚成相應(yīng)的類(lèi)。對(duì)K-means而言,首先是隨機(jī)產(chǎn)生于類(lèi)別數(shù)相同的初始點(diǎn),然后判斷每個(gè)點(diǎn)與初始點(diǎn)的距離,每個(gè)點(diǎn)選擇最近的一個(gè)初始點(diǎn),作為其類(lèi)別。

當(dāng)類(lèi)別產(chǎn)生后,在計(jì)算各個(gè)類(lèi)別的中心點(diǎn),然后計(jì)算每個(gè)點(diǎn)到中心點(diǎn)的距離,并根據(jù)距離再次選擇類(lèi)別。當(dāng)新類(lèi)別產(chǎn)生后,再次根據(jù)中心點(diǎn)重復(fù)選擇類(lèi)別的過(guò)程,直到中心點(diǎn)的變化不再明顯。最終根據(jù)中心點(diǎn)產(chǎn)生的類(lèi)別,就是聚類(lèi)的結(jié)果。正如圖中所示,一組對(duì)象中需要生成三個(gè)類(lèi)別,各個(gè)類(lèi)別之間都自然聚焦在一起。

在層次聚類(lèi)中,不需要規(guī)定出類(lèi)別的數(shù)量,最終聚類(lèi)的數(shù)量可以根據(jù)人為要求進(jìn)行劃分。對(duì)層次聚類(lèi),首先每個(gè)對(duì)象都是單獨(dú)的類(lèi)別,通過(guò)比較兩兩之間距離,首先把距離最小的兩個(gè)對(duì)象聚成一類(lèi)。接著把距離次小的聚成一類(lèi),然后就是不斷重復(fù)按距離最小的原則,不斷聚成一類(lèi)的過(guò)程,直到所有對(duì)象都被聚成一類(lèi)。

在層次聚類(lèi)中,可以以一張樹(shù)狀圖來(lái)表示聚類(lèi)的過(guò)程,如果要講對(duì)象分類(lèi)的話(huà),就可以從根節(jié)點(diǎn)觸發(fā),按照樹(shù)狀圖的分叉情況,劃分出不同的類(lèi)別來(lái)。在圖中,把一組對(duì)象分成了三個(gè)類(lèi)別,可見(jiàn)這三個(gè)類(lèi)別就是構(gòu)成了樹(shù)狀圖最開(kāi)始的三個(gè)分支。

k-means

首先,隨機(jī)選擇K個(gè)對(duì)象,并且所選擇的每個(gè)對(duì)象都代表一個(gè)組的初始均值或初始的組中心值;對(duì)剩余的每個(gè)對(duì)象,根據(jù)其與各個(gè)組初始均值的距離,將它們分配給最近的(最相似)小組;然后,重新計(jì)算每個(gè)小組新的均值;這個(gè)過(guò)程不斷重復(fù),直到所有的對(duì)象在K組分布中都找到離自己最近的組。

優(yōu)點(diǎn):容易實(shí)現(xiàn)。

缺點(diǎn):可能收斂到局部最小值,在大規(guī)模數(shù)據(jù)集上收斂較慢;
先指定k,同時(shí)對(duì)異常值很敏感。

聚類(lèi)技術(shù)在數(shù)據(jù)分析和數(shù)據(jù)化運(yùn)營(yíng)中的主要用途表現(xiàn)在:既可以直接作為模型對(duì)觀(guān)察對(duì)象進(jìn)行群體劃分,為業(yè)務(wù)方的精細(xì)化運(yùn)營(yíng)提供具體的細(xì)分依據(jù)和相應(yīng)的運(yùn)營(yíng)方案建議,又可在數(shù)據(jù)處理階段用作數(shù)據(jù)探索的工具,包括發(fā)現(xiàn)離群點(diǎn)、孤立點(diǎn),數(shù)據(jù)降維的手段和方法,通過(guò)聚類(lèi)發(fā)現(xiàn)數(shù)據(jù)間的深層次的關(guān)系等。

一、已知聚類(lèi)簇?cái)?shù)的iris數(shù)據(jù)集

# 導(dǎo)入第三方包
import pandas as pd
import numpy as np  
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import metrics
# 讀取iris數(shù)據(jù)集
iris = pd.read_csv(r'F:\iris.csv')
# 查看數(shù)據(jù)集的前幾行
iris.head()

不存在量綱上的差異,無(wú)需做標(biāo)準(zhǔn)化處理

聚類(lèi)簇?cái)?shù)為3,

# 提取出用于建模的數(shù)據(jù)集X
X = iris.drop(labels = 'Species', axis = 1)
# 構(gòu)建Kmeans模型
kmeans = KMeans(n_clusters = 3)
kmeans.fit(X)
# 聚類(lèi)結(jié)果標(biāo)簽
X['cluster'] = kmeans.labels_
# 各類(lèi)頻數(shù)統(tǒng)計(jì)
X.cluster.value_counts()

各簇樣本量分別為62,50,38

對(duì)比建模前后差異

# 導(dǎo)入第三方模塊
import seaborn as sns
# 中文和負(fù)號(hào)的正常顯示
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
import matplotlib.pyplot as plt
# 設(shè)置繪圖風(fēng)格
plt.style.use('ggplot')
# 三個(gè)簇的簇中心
centers = kmeans.cluster_centers_
# 繪制聚類(lèi)效果的散點(diǎn)圖
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('花瓣長(zhǎng)度')
plt.ylabel('花瓣寬度')
# 圖形顯示
plt.show()

以上為聚類(lèi)效果的散點(diǎn)圖,五角星為每個(gè)簇的簇中心

# 增加一個(gè)輔助列,將不同的花種映射到0,1,2三種值,目的方便后面圖形的對(duì)比
iris['Species_map'] = iris.Species.map({'virginica':0,'setosa':1,'versicolor':2})
# 繪制原始數(shù)據(jù)三個(gè)類(lèi)別的散點(diǎn)圖
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('花瓣長(zhǎng)度')
plt.ylabel('花瓣寬度')
# 圖形顯示
plt.show()

以上為原始數(shù)據(jù)的散點(diǎn)圖,與聚類(lèi)圖對(duì)比,標(biāo)記為1的與原始數(shù)據(jù)吻合,0和2存在一些錯(cuò)誤分割,但還是比較一致

對(duì)比樣本差異使用雷達(dá)圖,導(dǎo)入pygal模塊

# 導(dǎo)入第三方模塊
import pygal
# 調(diào)用Radar這個(gè)類(lèi),并設(shè)置雷達(dá)圖的填充,及數(shù)據(jù)范圍
radar_chart = pygal.Radar(fill = True)
# 添加雷達(dá)圖各頂點(diǎn)的名稱(chēng)
radar_chart.x_labels = ['花萼長(zhǎng)度','花萼寬度','花瓣長(zhǎng)度','花瓣寬度']

# 繪制三個(gè)雷達(dá)圖區(qū)域,代表三個(gè)簇中心的指標(biāo)值
radar_chart.add('C1', centers[0])
radar_chart.add('C2', centers[1])
radar_chart.add('C3', centers[2])
# 保存圖像
radar_chart.render_to_file('radar_chart.svg')

雷達(dá)圖無(wú)法通過(guò)plt.show展示,通過(guò)瀏覽器打開(kāi)svg文件


二、未知聚類(lèi)簇?cái)?shù)的NBA球員數(shù)據(jù)集

# 讀取球員數(shù)據(jù)
players = pd.read_csv(r'F:\players.csv')
players.head()
# 繪制得分與命中率的散點(diǎn)圖
sns.lmplot(x = '得分', y = '命中率', data = players, 
           fit_reg = False, scatter_kws = {'alpha':0.8, 'color': 'steelblue'})
plt.show()
from sklearn import preprocessing
# 數(shù)據(jù)標(biāo)準(zhǔn)化處理
X = preprocessing.minmax_scale(players[['得分','罰球命中率','命中率','三分命中率']])
# 將數(shù)組轉(zhuǎn)換為數(shù)據(jù)框
X = pd.DataFrame(X, columns=['得分','罰球命中率','命中率','三分命中率'])
X.head()

重點(diǎn)在于選擇最佳k值

1.拐點(diǎn)法

# 構(gòu)造自定義函數(shù),用于繪制不同k值和對(duì)應(yīng)總的簇內(nèi)離差平方和的折線(xiàn)圖
def k_SSE(X, clusters):
    # 選擇連續(xù)的K種不同的值
    K = range(1,clusters+1)
    # 構(gòu)建空列表用于存儲(chǔ)總的簇內(nèi)離差平方和
    TSSE = []
    for k in K:
        # 用于存儲(chǔ)各個(gè)簇內(nèi)離差平方和
        SSE = []
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        # 返回簇標(biāo)簽
        labels = kmeans.labels_
        # 返回簇中心
        centers = kmeans.cluster_centers_
        # 計(jì)算各簇樣本的離差平方和,并保存到列表中
        for label in set(labels):
            SSE.append(np.sum((X.loc[labels == label,]-centers[label,:])**2))
        # 計(jì)算總的簇內(nèi)離差平方和 
        TSSE.append(np.sum(SSE))

    # 中文和負(fù)號(hào)的正常顯示
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 設(shè)置繪圖風(fēng)格
    plt.style.use('ggplot')
    # 繪制K的個(gè)數(shù)與GSSE的關(guān)系
    plt.plot(K, TSSE, 'b*-')
    plt.xlabel('簇的個(gè)數(shù)')
    plt.ylabel('簇內(nèi)離差平方和之和')
    # 顯示圖形
    plt.show()
    
# 使用拐點(diǎn)法選擇最佳的K值
k_SSE(X, 15)

當(dāng)k在4附近,折線(xiàn)斜率的變動(dòng)不是很大,故k為3,或4或5

2,輪廓系數(shù)法

# 構(gòu)造自定義函數(shù),用于繪制不同k值和對(duì)應(yīng)輪廓系數(shù)的折線(xiàn)圖
def k_silhouette(X, clusters):
    K = range(2,clusters+1)
    # 構(gòu)建空列表,用于存儲(chǔ)個(gè)中簇?cái)?shù)下的輪廓系數(shù)
    S = []
    for k in K:
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        labels = kmeans.labels_
        # 調(diào)用字模塊metrics中的silhouette_score函數(shù),計(jì)算輪廓系數(shù)
        S.append(metrics.silhouette_score(X, labels, metric='euclidean'))

    # 中文和負(fù)號(hào)的正常顯示
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 設(shè)置繪圖風(fēng)格
    plt.style.use('ggplot')    
    # 繪制K的個(gè)數(shù)與輪廓系數(shù)的關(guān)系
    plt.plot(K, S, 'b*-')
    plt.xlabel('簇的個(gè)數(shù)')
    plt.ylabel('輪廓系數(shù)')
    # 顯示圖形
    plt.show()
    
# 使用輪廓系數(shù)選擇最佳的K值
k_silhouette(X, 15)

k=2時(shí)輪廓系數(shù)最大

3,間隔統(tǒng)計(jì)量法

# 自定義函數(shù),計(jì)算簇內(nèi)任意兩樣本之間的歐氏距離
def short_pair_wise_D(each_cluster):
    mu = each_cluster.mean(axis = 0)
    Dk = sum(sum((each_cluster - mu)**2)) * 2.0 * each_cluster.shape[0]
    return Dk

# 計(jì)算簇內(nèi)的Wk值
def compute_Wk(data, classfication_result):
    Wk = 0
    label_set = set(classfication_result)
    for label in label_set:
        each_cluster = data[classfication_result == label, :]
        Wk = Wk + short_pair_wise_D(each_cluster)/(2.0*each_cluster.shape[0])
    return Wk

# 計(jì)算GAP統(tǒng)計(jì)量 
def gap_statistic(X, B=10, K=range(1,11), N_init = 10):
    # 將輸入數(shù)據(jù)集轉(zhuǎn)換為數(shù)組
    X = np.array(X)
    # 生成B組參照數(shù)據(jù)
    shape = X.shape
    tops = X.max(axis=0)
    bots = X.min(axis=0)
    dists = np.matrix(np.diag(tops-bots))
    rands = np.random.random_sample(size=(B,shape[0],shape[1]))
    for i in range(B):
        rands[i,:,:] = rands[i,:,:]*dists+bots
    
    # 自定義0元素的數(shù)組,用于存儲(chǔ)gaps、Wks和Wkbs
    gaps = np.zeros(len(K))
    Wks = np.zeros(len(K))
    Wkbs = np.zeros((len(K),B))
    # 循環(huán)不同的k值,
    for idxk, k in enumerate(K):
        k_means =  KMeans(n_clusters=k)
        k_means.fit(X)
        classfication_result = k_means.labels_
        # 將所有簇內(nèi)的Wk存儲(chǔ)起來(lái)
        Wks[idxk] = compute_Wk(X,classfication_result)
        
        # 通過(guò)循環(huán),計(jì)算每一個(gè)參照數(shù)據(jù)集下的各簇Wk值
        for i in range(B):
            Xb = rands[i,:,:]
            k_means.fit(Xb)
            classfication_result_b = k_means.labels_
            Wkbs[idxk,i] = compute_Wk(Xb,classfication_result_b)

    # 計(jì)算gaps、sd_ks、sk和gapDiff
    gaps = (np.log(Wkbs)).mean(axis = 1) - np.log(Wks)        
    sd_ks = np.std(np.log(Wkbs), axis=1)
    sk = sd_ks*np.sqrt(1+1.0/B)
    # 用于判別最佳k的標(biāo)準(zhǔn),當(dāng)gapDiff首次為正時(shí),對(duì)應(yīng)的k即為目標(biāo)值
    gapDiff = gaps[:-1] - gaps[1:] + sk[1:]
    
    # 中文和負(fù)號(hào)的正常顯示
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 設(shè)置繪圖風(fēng)格
    plt.style.use('ggplot')
    # 繪制gapDiff的條形圖
    plt.bar(np.arange(len(gapDiff))+1, gapDiff, color = 'steelblue')
    plt.xlabel('簇的個(gè)數(shù)')
    plt.ylabel('k的選擇標(biāo)準(zhǔn)')
    plt.show()
    
# 使用間隙統(tǒng)計(jì)量選擇最佳的K值
gap_statistic(X, B = 20, K=range(1, 16))

縱坐標(biāo)首次為正時(shí)k=3

綜合考慮以上3種,選擇k=3

基于k值進(jìn)行聚類(lèi)

# 將球員數(shù)據(jù)集聚為3類(lèi)
kmeans = KMeans(n_clusters = 3)
kmeans.fit(X)
# 將聚類(lèi)結(jié)果標(biāo)簽插入到數(shù)據(jù)集players中
players['cluster'] = kmeans.labels_
# 構(gòu)建空列表,用于存儲(chǔ)三個(gè)簇的簇中心
centers = []
for i in players.cluster.unique():
    centers.append(players.ix[players.cluster == i,['得分','罰球命中率','命中率','三分命中率']].mean())
# 將列表轉(zhuǎn)換為數(shù)組,便于后面的索引取數(shù)
centers = np.array(centers)
centers
# 繪制散點(diǎn)圖
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()

需要注意的是,由于對(duì)原數(shù)據(jù)做了標(biāo)準(zhǔn)化處理,簇中心不能直接使用cluster_centers_得到,返回的是原數(shù)據(jù)標(biāo)準(zhǔn)化后的中心,需要通過(guò)For循環(huán)重新找到原始數(shù)據(jù)下的簇中心,即五角星



可以得到高得分高命中率型諸如此類(lèi)

再看四個(gè)指標(biāo)上的差異,由于四個(gè)維度上量綱不一致,需要使用標(biāo)準(zhǔn)化后的中心點(diǎn)繪制雷達(dá)圖

# 雷達(dá)圖
# 調(diào)用模型計(jì)算出來(lái)的簇中心
centers_std = kmeans.cluster_centers_
# 設(shè)置填充型雷達(dá)圖
radar_chart = pygal.Radar(fill = True)
# 添加雷達(dá)圖各頂點(diǎn)的名稱(chēng)
radar_chart.x_labels = ['得分','罰球命中率','命中率','三分命中率']

# 繪制雷達(dá)圖代表三個(gè)簇中心的指標(biāo)值
radar_chart.add('C1', centers_std[0])
radar_chart.add('C2', centers_std[1])
radar_chart.add('C3', centers_std[2])
# 保存圖像
radar_chart.render_to_file('radar_chart.svg')

C2、C3得分沒(méi)有差異,但命中率C2比C3高很多諸如此類(lèi)結(jié)論

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容