知識篇——聚類算法應用

時隔兩月開始繼續儲備機器學習的知識,監督學習已經告一段落,非監督學習從聚類開始。
非監督學習與監督學習最大的區別在於目標變量事先不存在,也就是說

監督學習可以做到“對於輸入數據X能預測變量Y”,而非監督學習能做到的是“從數據X中能發現什麼?”,比如“構成X的最佳6個數據簇都是哪些?”或者“X中哪三個特徵最頻繁共現?”

這就很好玩了,比如我在Udacity的第三個項目,一家批發經銷商想將發貨方式從每週五次減少到每週三次,簡稱成本,但是造成一些客戶的不滿意,取消了提貨,帶來更大虧損,項目要求是通過分析客戶類別,選擇合適的發貨方式,達到技能降低成本又能降低客戶不滿意度的目的。

什麼是聚類

聚類將相似的對象歸到同一個簇中,幾乎可以應用於所有對象,聚類的對象越相似,聚類效果越好。聚類與分類的不同之處在於分類預先知道所分的類到底是什麼,而聚類則預先不知道目標,但是可以通過簇識別(cluster identification)告訴我們這些簇到底都是什麼。

K-means

聚類的一種,之所以叫k-均值是因爲它可以發現k個不同的簇,且每個簇的中心採用簇中所含值的均值計算而成。簇個數k是用戶給定的,每一個簇通過質心來描述。

k-means的工作流程是:
- 隨機確定k個初始點做爲質心
- 給數據集中的每個點找距其最近的質心,並分配到該簇
- 將每個簇的質心更新爲該簇所有點的平均值
- 循環上兩部,直到每個點的簇分配結果不在改變爲止

項目流程

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

顯示數據的一個描述

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

分析數據是一門學問,感覺自己在這方面還需要多加練習,數據描述包含數據總數,特徵,每個特徵的均值,標準差,還有最小值、25%、50%、75%、最大值處的值,這些都可以很容易列出來,但是透過這些數據需要看到什麼信息,如何與需求目的結合,最開始還是比較吃力的。可以先選擇幾個數值差異較大的樣本,然後結合數據描述和需求,對數據整體有一個把控。比如在Udacity的第三個項目中,給出客戶針對不同類型產品的年度採購額,分析猜測每個樣本客戶的類型。
數據描述

三個樣本客戶
樣本客戶
每個客戶究竟是什麼類型,這個問題困擾我好久,第一次回答我只是看那個方面採購額最大,就給它一個最近的類型,提交項目後Reviewer這樣建議:

這裏有一個問題, 你在討論一個樣本對某產品的採購時沒有以統計數據爲參考. 注意, “大量” 和 “少量” 的描述都應該相對於統計數據而言.
提示: 從data.describe()中你已經得到了均值和四分位數, 把它們利用起來.

恍然大悟,這才知道了該如何分析一份數據集,於是有了下面的回答

回答

所以分析數據一定要結合統計數據,四分位數和均值可以看做數據的骨架,能夠一定程度勾勒出數據的分佈,可以通過箱線圖來可視化四分位數。

分析特徵相關性

特徵之間通常都有相關性,可以通過用移除某個特徵後的數據集構建一個監督學習模型,用其餘特徵預測移除的特徵,對結果進行評分的方法來判斷特徵間的相關性。比如用決策樹迴歸模型和R2分數來判斷某個特徵是否必要。

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);

如果是負數,說明該特徵絕對不能少,因爲缺少了就無法擬合數據。如果是1,表示少了也無所謂,有一個跟它相關聯的特徵能代替它,如果是0到1間的其他數,則可以少,只是有一定的影響,越靠近0,影響越大。

也可以通過散佈矩陣(scatter matrix)來可視化特徵分佈,如果一個特徵是必須的,則它和其他特徵可能不會顯示任何關係,如果不是必須的,則可能和某個特徵呈線性或其他關係。

# 對於數據中的每一對特徵構造一個散佈矩陣
pd.tools.plotting.scatter_matrix(data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

散佈矩陣圖舉例

數據預處理

(一)特徵縮放
如果數據特徵呈偏態分佈,通常進行非線性縮放。

# 使用自然對數縮放數據
log_data = np.log(data);

# 爲每一對新產生的特徵製作一個散射矩陣
pd.tools.plotting.scatter_matrix(log_data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

可以發現散佈矩陣變成了下圖

特徵縮放後的散佈矩陣
(二)異常值檢測
通常用Tukey的定義異常值的方法檢測異常值。

一個異常階(outlier step)被定義成1.5倍的四分位距(interquartile range,IQR)。一個數據點如果某個特徵包含在該特徵的IQR之外的特徵,那麼該數據點被認定爲異常點。

# 對於每一個特徵,找到值異常高或者是異常低的數據點
for feature in log_data.keys():

    # 計算給定特徵的Q1(數據的25th分位點)
    Q1 = np.percentile(log_data[feature], 25);

    #計算給定特徵的Q3(數據的75th分位點)
    Q3 = np.percentile(log_data[feature], 75);

    #使用四分位範圍計算異常階(1.5倍的四分位距)
    step = (Q3 - Q1) * 1.5;

    # 顯示異常點
    print "Data points considered outliers for the feature '{}':".format(feature)
    display(log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))])

# 可選:選擇你希望移除的數據點的索引
outliers  = [65, 66, 75, 154, 128];

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

移除異常值需要具體情況具體考慮,但是要謹慎,因爲我們需要充分理解數據,記錄號移除的點以及移除原因。可以用counter來輔助尋找出現次數大於1的離羣點。

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

(三)特徵轉換
特徵轉換主要用到主成分分析發,請查看之前介紹

聚類

有些問題的聚類數目可能是已知的,但是我們並不能保證某個聚類的數目對這個數據是最優的,因爲我們對數據的結構是不清楚的。但是我們可以通過計算每一個簇中點的輪廓係數來衡量聚類的質量。數據點的輪廓係數衡量了分配給它的簇的相似度,範圍-1(不相似)到1(相似)。平均輪廓係數爲我們提供了一種簡單地度量聚類質量的方法。
下面代碼會顯示聚類數爲2時的平均輪廓係數,可以修改n_clusters來得到不同聚類數目下的平均輪廓係數。


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

# 預測每一個點的簇
preds = clusterer.predict(reduced_data);

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

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

如果用對數做了降維,可以用指數將數據恢復。

發佈了97 篇原創文章 · 獲贊 41 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章