知識(shí)篇——聚類算法應(yīng)用

時(shí)隔兩月開(kāi)始繼續(xù)儲(chǔ)備機(jī)器學(xué)習(xí)的知識(shí),監(jiān)督學(xué)習(xí)已經(jīng)告一段落,非監(jiān)督學(xué)習(xí)從聚類開(kāi)始。
非監(jiān)督學(xué)習(xí)與監(jiān)督學(xué)習(xí)最大的區(qū)別在于目標(biāo)變量事先不存在,也就是說(shuō)

監(jiān)督學(xué)習(xí)可以做到“對(duì)于輸入數(shù)據(jù)X能預(yù)測(cè)變量Y”,而非監(jiān)督學(xué)習(xí)能做到的是“從數(shù)據(jù)X中能發(fā)現(xiàn)什么?”,比如“構(gòu)成X的最佳6個(gè)數(shù)據(jù)簇都是哪些?”或者“X中哪三個(gè)特征最頻繁共現(xiàn)?”

這就很好玩了,比如我在Udacity的第三個(gè)項(xiàng)目,一家批發(fā)經(jīng)銷商想將發(fā)貨方式從每周五次減少到每周三次,簡(jiǎn)稱成本,但是造成一些客戶的不滿意,取消了提貨,帶來(lái)更大虧損,項(xiàng)目要求是通過(guò)分析客戶類別,選擇合適的發(fā)貨方式,達(dá)到技能降低成本又能降低客戶不滿意度的目的。

什么是聚類

聚類將相似的對(duì)象歸到同一個(gè)簇中,幾乎可以應(yīng)用于所有對(duì)象,聚類的對(duì)象越相似,聚類效果越好。聚類與分類的不同之處在于分類預(yù)先知道所分的類到底是什么,而聚類則預(yù)先不知道目標(biāo),但是可以通過(guò)簇識(shí)別(cluster identification)告訴我們這些簇到底都是什么。

K-means

聚類的一種,之所以叫k-均值是因?yàn)樗梢园l(fā)現(xiàn)k個(gè)不同的簇,且每個(gè)簇的中心采用簇中所含值的均值計(jì)算而成。簇個(gè)數(shù)k是用戶給定的,每一個(gè)簇通過(guò)質(zhì)心來(lái)描述。

k-means的工作流程是:

  • 隨機(jī)確定k個(gè)初始點(diǎn)做為質(zhì)心
  • 給數(shù)據(jù)集中的每個(gè)點(diǎn)找距其最近的質(zhì)心,并分配到該簇
  • 將每個(gè)簇的質(zhì)心更新為該簇所有點(diǎn)的平均值
  • 循環(huán)上兩部,直到每個(gè)點(diǎn)的簇分配結(jié)果不在改變?yōu)橹?/li>

項(xiàng)目流程

載入數(shù)據(jù)集
import pandas as pd
data = pd.read_csv("customers.csv");
分析數(shù)據(jù)

顯示數(shù)據(jù)的一個(gè)描述

from IPython.display import display
display(data.discrie());

分析數(shù)據(jù)是一門(mén)學(xué)問(wèn),感覺(jué)自己在這方面還需要多加練習(xí),數(shù)據(jù)描述包含數(shù)據(jù)總數(shù),特征,每個(gè)特征的均值,標(biāo)準(zhǔn)差,還有最小值、25%、50%、75%、最大值處的值,這些都可以很容易列出來(lái),但是透過(guò)這些數(shù)據(jù)需要看到什么信息,如何與需求目的結(jié)合,最開(kāi)始還是比較吃力的??梢韵冗x擇幾個(gè)數(shù)值差異較大的樣本,然后結(jié)合數(shù)據(jù)描述和需求,對(duì)數(shù)據(jù)整體有一個(gè)把控。比如在Udacity的第三個(gè)項(xiàng)目中,給出客戶針對(duì)不同類型產(chǎn)品的年度采購(gòu)額,分析猜測(cè)每個(gè)樣本客戶的類型。

數(shù)據(jù)描述

三個(gè)樣本客戶


樣本客戶

每個(gè)客戶究竟是什么類型,這個(gè)問(wèn)題困擾我好久,第一次回答我只是看那個(gè)方面采購(gòu)額最大,就給它一個(gè)最近的類型,提交項(xiàng)目后Reviewer這樣建議:

這里有一個(gè)問(wèn)題, 你在討論一個(gè)樣本對(duì)某產(chǎn)品的采購(gòu)時(shí)沒(méi)有以統(tǒng)計(jì)數(shù)據(jù)為參考. 注意, "大量" 和 "少量" 的描述都應(yīng)該相對(duì)于統(tǒng)計(jì)數(shù)據(jù)而言.
提示: 從data.describe()中你已經(jīng)得到了均值和四分位數(shù), 把它們利用起來(lái).

恍然大悟,這才知道了該如何分析一份數(shù)據(jù)集,于是有了下面的回答

回答

所以分析數(shù)據(jù)一定要結(jié)合統(tǒng)計(jì)數(shù)據(jù),四分位數(shù)和均值可以看做數(shù)據(jù)的骨架,能夠一定程度勾勒出數(shù)據(jù)的分布,可以通過(guò)箱線圖來(lái)可視化四分位數(shù)。

分析特征相關(guān)性

特征之間通常都有相關(guān)性,可以通過(guò)用移除某個(gè)特征后的數(shù)據(jù)集構(gòu)建一個(gè)監(jiān)督學(xué)習(xí)模型,用其余特征預(yù)測(cè)移除的特征,對(duì)結(jié)果進(jìn)行評(píng)分的方法來(lái)判斷特征間的相關(guān)性。比如用決策樹(shù)回歸模型和R2分?jǐn)?shù)來(lái)判斷某個(gè)特征是否必要。

from sklearn.model_selection import train_test_split
from sklearn import tree
new_data = data.drop('Feature name', axis = 1);
X_train, X_test, y_train, y_test = train_test_split(new_data, data['Feature name'], test_size = 0.25, random_state = 50)
regressor = tree.DecisionTreeRegressor(random_state = 50).fit(X_train, y_train);
score = regressor.score(X_test, y_test)
print(score);

如果是負(fù)數(shù),說(shuō)明該特征絕對(duì)不能少,因?yàn)槿鄙倭司蜔o(wú)法擬合數(shù)據(jù)。如果是1,表示少了也無(wú)所謂,有一個(gè)跟它相關(guān)聯(lián)的特征能代替它,如果是0到1間的其他數(shù),則可以少,只是有一定的影響,越靠近0,影響越大。

也可以通過(guò)散布矩陣(scatter matrix)來(lái)可視化特征分布,如果一個(gè)特征是必須的,則它和其他特征可能不會(huì)顯示任何關(guān)系,如果不是必須的,則可能和某個(gè)特征呈線性或其他關(guān)系。

# 對(duì)于數(shù)據(jù)中的每一對(duì)特征構(gòu)造一個(gè)散布矩陣
pd.tools.plotting.scatter_matrix(data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');
散布矩陣圖舉例
數(shù)據(jù)預(yù)處理

(一)特征縮放
如果數(shù)據(jù)特征呈偏態(tài)分布,通常進(jìn)行非線性縮放。

# 使用自然對(duì)數(shù)縮放數(shù)據(jù)
log_data = np.log(data);

# 為每一對(duì)新產(chǎn)生的特征制作一個(gè)散射矩陣
pd.tools.plotting.scatter_matrix(log_data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

可以發(fā)現(xiàn)散布矩陣變成了下圖

特征縮放后的散布矩陣

(二)異常值檢測(cè)
通常用Tukey的定義異常值的方法檢測(cè)異常值。

一個(gè)異常階(outlier step)被定義成1.5倍的四分位距(interquartile range,IQR)。一個(gè)數(shù)據(jù)點(diǎn)如果某個(gè)特征包含在該特征的IQR之外的特征,那么該數(shù)據(jù)點(diǎn)被認(rèn)定為異常點(diǎn)。

# 對(duì)于每一個(gè)特征,找到值異常高或者是異常低的數(shù)據(jù)點(diǎn)
for feature in log_data.keys():
  
    # 計(jì)算給定特征的Q1(數(shù)據(jù)的25th分位點(diǎn))
    Q1 = np.percentile(log_data[feature], 25);

    #計(jì)算給定特征的Q3(數(shù)據(jù)的75th分位點(diǎn))
    Q3 = np.percentile(log_data[feature], 75);
  
    #使用四分位范圍計(jì)算異常階(1.5倍的四分位距)
    step = (Q3 - Q1) * 1.5;
    
    # 顯示異常點(diǎn)
    print "Data points considered outliers for the feature '{}':".format(feature)
    display(log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))])
    
# 可選:選擇你希望移除的數(shù)據(jù)點(diǎn)的索引
outliers  = [65, 66, 75, 154, 128];

# 如果選擇了的話,移除異常點(diǎn)
good_data = log_data.drop(log_data.index[outliers]).reset_index(drop = True)

移除異常值需要具體情況具體考慮,但是要謹(jǐn)慎,因?yàn)槲覀冃枰浞掷斫鈹?shù)據(jù),記錄號(hào)移除的點(diǎn)以及移除原因??梢杂胏ounter來(lái)輔助尋找出現(xiàn)次數(shù)大于1的離群點(diǎn)。

from collections import Counter
print dict(Counter(['a', 'b', 'c', 'a', 'b', 'b']))  # {'b': 3, 'a': 2, 'c': 1}

(三)特征轉(zhuǎn)換
特征轉(zhuǎn)換主要用到主成分分析發(fā),請(qǐng)查看之前介紹。

聚類

有些問(wèn)題的聚類數(shù)目可能是已知的,但是我們并不能保證某個(gè)聚類的數(shù)目對(duì)這個(gè)數(shù)據(jù)是最優(yōu)的,因?yàn)槲覀儗?duì)數(shù)據(jù)的結(jié)構(gòu)是不清楚的。但是我們可以通過(guò)計(jì)算每一個(gè)簇中點(diǎn)的輪廓系數(shù)來(lái)衡量聚類的質(zhì)量。數(shù)據(jù)點(diǎn)的輪廓系數(shù)衡量了分配給它的簇的相似度,范圍-1(不相似)到1(相似)。平均輪廓系數(shù)為我們提供了一種簡(jiǎn)單地度量聚類質(zhì)量的方法。
下面代碼會(huì)顯示聚類數(shù)為2時(shí)的平均輪廓系數(shù),可以修改n_clusters來(lái)得到不同聚類數(shù)目下的平均輪廓系數(shù)。


from sklearn.cluster import KMeans
clusterer = KMeans(n_clusters=2, random_state=50).fit(reduced_data);

# 預(yù)測(cè)每一個(gè)點(diǎn)的簇
preds = clusterer.predict(reduced_data);

# 找到聚類中心
centers = clusterer.cluster_centers_;

# 計(jì)算選擇的類別的平均輪廓系數(shù)(mean silhouette coefficient)
from sklearn.metrics import silhouette_score
score = silhouette_score(reduced_data, preds);
數(shù)據(jù)恢復(fù)

如果用對(duì)數(shù)做了降維,可以用指數(shù)將數(shù)據(jù)恢復(fù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容