歡迎來到機器學習工程師納米學位的第三個項目!在這個notebook文件中,有些模板代碼已經提供給你,但你還須要實現更多的功能來完成這個項目。除非有明確要求,你無須修改任何已給出的代碼。以'練習'開始的標題表示接下來的代碼部分中有你必需要實現的功能。每一部分都會有詳細的指導,須要實現的部分也會在註釋中以'TODO'標出。請仔細閱讀全部的提示!javascript
除了實現代碼外,你還必須回答一些與項目和你的實現有關的問題。每個須要你回答的問題都會以'問題 X'爲標題。請仔細閱讀每一個問題,而且在問題後的'回答'文字框中寫出完整的答案。咱們將根據你對問題的回答和撰寫代碼所實現的功能來對你提交的項目進行評分。php
提示:Code 和 Markdown 區域可經過 Shift + Enter 快捷鍵運行。此外,Markdown能夠經過雙擊進入編輯模式。css
在這個項目中,你將分析一個數據集的內在結構,這個數據集包含不少客戶真對不一樣類型產品的年度採購額(用金額表示)。這個項目的任務之一是如何最好地描述一個批發商不一樣種類顧客之間的差別。這樣作將可以使得批發商可以更好的組織他們的物流服務以知足每一個客戶的需求。html
這個項目的數據集可以在UCI機器學習信息庫中找到.由於這個項目的目的,分析將不會包括'Channel'和'Region'這兩個特徵——重點集中在6個記錄的客戶購買的產品類別上。html5
運行下面的的代碼單元以載入整個客戶數據集和一些這個項目須要的Python庫。若是你的數據集載入成功,你將看到後面輸出數據集的大小。java
# 檢查你的Python版本
from sys import version_info
if version_info.major != 2 and version_info.minor != 7:
raise Exception('請使用Python 2.7來完成此項目')
# 引入這個項目須要的庫
import numpy as np
import pandas as pd
import visuals as vs
from IPython.display import display # 使得咱們能夠對DataFrame使用display()函數
# 設置之內聯的形式顯示matplotlib繪製的圖片(在notebook中顯示更美觀)
%matplotlib inline
# 載入整個客戶數據集
try:
data = pd.read_csv("customers.csv")
data.drop(['Region', 'Channel'], axis = 1, inplace = True)
print "Wholesale customers dataset has {} samples with {} features each.".format(*data.shape)
except:
print "Dataset could not be loaded. Is the dataset missing?"
在這部分,你將開始分析數據,經過可視化和代碼來理解每個特徵和其餘特徵的聯繫。你會看到關於數據集的統計描述,考慮每個屬性的相關性,而後從數據集中選擇若干個樣本數據點,你將在整個項目中一直跟蹤研究這幾個數據點。node
運行下面的代碼單元給出數據集的一個統計描述。注意這個數據集包含了6個重要的產品類型:'Fresh', 'Milk', 'Grocery', 'Frozen', 'Detergents_Paper'和 'Delicatessen'。想一下這裏每個類型表明你會購買什麼樣的產品。python
# 顯示數據集的一個描述
display(data.describe())
爲了對客戶有一個更好的瞭解,而且瞭解表明他們的數據將會在這個分析過程當中如何變換。最好是選擇幾個樣本數據點,而且更爲詳細地分析它們。在下面的代碼單元中,選擇三個索引加入到索引列表indices
中,這三個索引表明你要追蹤的客戶。咱們建議你不斷嘗試,直到找到三個明顯不一樣的客戶。jquery
# TODO:從數據集中選擇三個你但願抽樣的數據點的索引
indices = [2, 9, 200]
# 爲選擇的樣本創建一個DataFrame
samples = pd.DataFrame(data.loc[indices], columns = data.keys()).reset_index(drop = True)
print "Chosen samples of wholesale customers dataset:"
display(samples)
在你看來你選擇的這三個樣本點分別表明什麼類型的企業(客戶)?對每個你選擇的樣本客戶,經過它在每一種產品類型上的花費與數據集的統計描述進行比較,給出你作上述判斷的理由。linux
提示: 企業的類型包括超市、咖啡館、零售商以及其餘。注意不要使用具體企業的名字,好比說在描述一個餐飲業客戶時,你不能使用麥當勞。
回答:
0號樣本表明零售商,Fresh在50%,Milk在75%,Grocery在75%,Frozen在50%,Detergents_Paper在75%,Delicatessen在75%,全部基本都在平均數左右,表明每樣東西都有一些,可是都不算特別多,且沒有某列數據特別多,因此是零售商的可能性較大
1號樣本表明其餘,Fresh在75%,Milk在75%,Grocery在75%,Frozen在50%,Detergents_Paper在75%,Delicatessen在75%,大部分數據都超過平均值,類型廣沒有特別類型突出,因此是一個大型超市的可能性比較大
2號樣本表明,Fresh在25%,Milk在75%以上,Grocery在75%以上,Frozen在75%以上,Detergents_Paper在75%以上,Delicatessen在25%,多是奶茶店
一個有趣的想法是,考慮這六個類別中的一個(或者多個)產品類別,是否對於理解客戶的購買行爲具備實際的相關性。也就是說,當用戶購買了必定數量的某一類產品,咱們是否可以肯定他們必然會成比例地購買另外一種類的產品。有一個簡單的方法能夠檢測相關性:咱們用移除了某一個特徵以後的數據集來構建一個監督學習(迴歸)模型,而後用這個模型去預測那個被移除的特徵,再對這個預測結果進行評分,看看預測結果如何。
在下面的代碼單元中,你須要實現如下的功能:
DataFrame.drop
函數移除數據集中你選擇的不須要的特徵,並將移除後的結果賦值給new_data
。sklearn.model_selection.train_test_split
將數據集分割成訓練集和測試集。
test_size
爲0.25
並設置一個random_state
。random_state
,而後用訓練集訓練它。score
函數輸出模型在測試集上的預測得分。# TODO:爲DataFrame建立一個副本,用'drop'函數丟棄一個特徵
new_data = data.drop(['Fresh'],axis=1)
labels = data['Fresh']
# TODO:使用給定的特徵做爲目標,將數據分割成訓練集和測試集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(new_data, labels, test_size=0.25, random_state=1)
# TODO:建立一個DecisionTreeRegressor(決策樹迴歸器)並在訓練集上訓練它
from sklearn.tree import DecisionTreeRegressor
regressor = DecisionTreeRegressor(random_state=0)
regressor.fit(X_train,y_train)
y_pred = regressor.predict(X_test)
# TODO:輸出在測試集上的預測得分
from sklearn.metrics import r2_score
score = r2_score(y_test,y_pred)
print score
你嘗試預測哪個特徵?預測的得分是多少?這個特徵對於區分用戶的消費習慣來講必要嗎?爲何?
提示: 決定係數(coefficient of determination), R^2
,結果在0到1之間,1表示完美擬合,一個負的R^2
表示模型不可以擬合數據。
回答:
爲了可以對這個數據集有一個更好的理解,咱們能夠對數據集中的每個產品特徵構建一個散佈矩陣(scatter matrix)。若是你發現你在上面嘗試預測的特徵對於區分一個特定的用戶來講是必須的,那麼這個特徵和其它的特徵可能不會在下面的散射矩陣中顯示任何關係。相反的,若是你認爲這個特徵對於識別一個特定的客戶是沒有做用的,那麼經過散佈矩陣能夠看出在這個數據特徵和其它特徵中有關聯性。運行下面的代碼以建立一個散佈矩陣。
# 對於數據中的每一對特徵構造一個散佈矩陣
pd.plotting.scatter_matrix(data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');
這裏是否存在一些特徵他們彼此之間存在必定程度相關性?若是有請列出。這個結果是驗證了仍是否定了你嘗試預測的那個特徵的相關性?這些特徵的數據是怎麼分佈的?
提示: 這些數據是正態分佈(normally distributed)的嗎?大多數的數據點分佈在哪?
回答:
在這個部分,你將經過在數據上作一個合適的縮放,並檢測異常點(你能夠選擇性移除)將數據預處理成一個更好的表明客戶的形式。預處理數據是保證你在分析中可以獲得顯著且有意義的結果的重要環節。
若是數據不是正態分佈的,尤爲是數據的平均數和中位數相差很大的時候(表示數據很是歪斜)。這時候一般用一個非線性的縮放是很合適的,(英文原文) — 尤爲是對於金融數據。一種實現這個縮放的方法是使用Box-Cox 變換,這個方法可以計算出可以最佳減少數據傾斜的指數變換方法。一個比較簡單的而且在大多數狀況下都適用的方法是使用天然對數。
在下面的代碼單元中,你將須要實現如下功能:
np.log
函數在數據 data
上作一個對數縮放,而後將它的副本(不改變原始data的值)賦值給log_data
。np.log
函數在樣本數據 samples
上作一個對數縮放,而後將它的副本賦值給log_samples
。# TODO:使用天然對數縮放數據
log_data = np.log(data)
# TODO:使用天然對數縮放樣本數據
log_samples = np.log(samples)
# 爲每一對新產生的特徵製做一個散射矩陣
pd.plotting.scatter_matrix(log_data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');
在使用了一個天然對數的縮放以後,數據的各個特徵會顯得更加的正態分佈。對於任意的你之前發現有相關關係的特徵對,觀察他們的相關關係是否仍是存在的(而且嘗試觀察,他們的相關關係相比原來是變強了仍是變弱了)。
運行下面的代碼以觀察樣本數據在進行了天然對數轉換以後如何改變了。
# 展現通過對數變換後的樣本數據
display(log_samples)
對於任何的分析,在數據預處理的過程當中檢測數據中的異常值都是很是重要的一步。異常值的出現會使得把這些值考慮進去後結果出現傾斜。這裏有不少關於怎樣定義什麼是數據集中的異常值的經驗法則。這裏咱們將使用Tukey的定義異常值的方法:一個異常階(outlier step)被定義成1.5倍的四分位距(interquartile range,IQR)。一個數據點若是某個特徵包含在該特徵的IQR以外的特徵,那麼該數據點被認定爲異常點。
在下面的代碼單元中,你須要完成下面的功能:
Q1
。使用np.percentile
來完成這個功能。Q3
。一樣的,使用np.percentile
來完成這個功能。step
.outliers
列表中,以移除異常值。注意: 若是你選擇移除異常值,請保證你選擇的樣本點不在這些移除的點當中! 一旦你完成了這些功能,數據集將存儲在good_data
中。
outliers = []
# 對於每個特徵,找到值異常高或者是異常低的數據點
for feature in log_data.keys():
# TODO:計算給定特徵的Q1(數據的25th分位點)
Q1 = np.percentile(log_data[feature], 25)
# TODO:計算給定特徵的Q3(數據的75th分位點)
Q3 = np.percentile(log_data[feature], 75)
# TODO:使用四分位範圍計算異常階(1.5倍的四分位距)
step = (Q3 - Q1) * 1.5
outdatas = log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))]
outliers.extend(outdatas.index.tolist())
# 顯示異常點
print "Data points considered outliers for the feature '{}':".format(feature)
display(log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))])
# 可選:選擇你但願移除的數據點的索引
# outliers = []
outliers = [val for val in list(set(outliers)) if outliers.count(val)>=2]
print outliers
# 若是選擇了的話,移除異常點
good_data = log_data.drop(log_data.index[outliers]).reset_index(drop = True)
請列出全部在多於一個特徵下被看做是異常的數據點。這些點應該被從數據集中移除嗎?爲何?把你認爲須要移除的數據點所有加入到到outliers
變量中。
回答:
在這個部分中你將使用主成分分析(PCA)來分析批發商客戶數據的內在結構。因爲使用PCA在一個數據集上會計算出最大化方差的維度,咱們將找出哪個特徵組合可以最好的描繪客戶。
既然數據被縮放到一個更加正態分佈的範圍中而且咱們也移除了須要移除的異常點,咱們如今就可以在good_data
上使用PCA算法以發現數據的哪個維度可以最大化特徵的方差。除了找到這些維度,PCA也將報告每個維度的解釋方差比(explained variance ratio)--這個數據有多少方差可以用這個單獨的維度來解釋。注意PCA的一個組成部分(維度)可以被看作這個空間中的一個新的「特徵」,可是它是原來數據中的特徵構成的。
在下面的代碼單元中,你將要實現下面的功能:
sklearn.decomposition.PCA
而且將good_data
用PCA而且使用6個維度進行擬合後的結果保存到pca
中。pca.transform
將log_samples
進行轉換,並將結果存儲到pca_samples
中。# TODO:經過在good_data上使用PCA,將其轉換成和當前特徵數同樣多的維度
from sklearn.decomposition import PCA
pca = PCA(n_components=6)
pca.fit(good_data)
# TODO:使用上面的PCA擬合將變換施加在log_samples上
pca_samples = pca.transform(log_samples)
# 生成PCA的結果圖
pca_results = vs.pca_results(good_data, pca)
回答:
運行下面的代碼,查看通過對數轉換的樣本數據在進行一個6個維度的主成分分析(PCA)以後會如何改變。觀察樣本數據的前四個維度的數值。考慮這和你初始對樣本點的解釋是否一致。
# 展現通過PCA轉換的sample log-data
display(pd.DataFrame(np.round(pca_samples, 4), columns = pca_results.index.values))
當使用主成分分析的時候,一個主要的目的是減小數據的維度,這實際上下降了問題的複雜度。固然降維也是須要必定代價的:更少的維度可以表示的數據中的總方差更少。由於這個,累計解釋方差比(cumulative explained variance ratio)對於咱們肯定這個問題須要多少維度很是重要。另外,若是大部分的方差都可以經過兩個或者是三個維度進行表示的話,降維以後的數據可以被可視化。
在下面的代碼單元中,你將實現下面的功能:
good_data
用兩個維度的PCA進行擬合,並將結果存儲到pca
中去。pca.transform
將good_data
進行轉換,並將結果存儲在reduced_data
中。pca.transform
將log_samples
進行轉換,並將結果存儲在pca_samples
中。# TODO:經過在good data上進行PCA,將其轉換成兩個維度
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
pca.fit(good_data)
# TODO:使用上面訓練的PCA將good data進行轉換
reduced_data = pca.transform(good_data)
# TODO:使用上面訓練的PCA將log_samples進行轉換
pca_samples = pca.transform(log_samples)
# 爲降維後的數據建立一個DataFrame
reduced_data = pd.DataFrame(reduced_data, columns = ['Dimension 1', 'Dimension 2'])
運行如下代碼觀察當僅僅使用兩個維度進行PCA轉換後,這個對數樣本數據將怎樣變化。觀察這裏的結果與一個使用六個維度的PCA轉換相比較時,前兩維的數值是保持不變的。
# 展現通過兩個維度的PCA轉換以後的樣本log-data
display(pd.DataFrame(np.round(pca_samples, 4), columns = ['Dimension 1', 'Dimension 2']))
雙標圖是一個散點圖,每一個數據點的位置由它所在主成分的分數肯定。座標系是主成分(這裏是Dimension 1
和 Dimension 2
)。此外,雙標圖還展現出初始特徵在主成分上的投影。一個雙標圖能夠幫助咱們理解降維後的數據,發現主成分和初始特徵之間的關係。
運行下面的代碼來建立一個降維後數據的雙標圖。
# Create a biplot
vs.biplot(good_data, reduced_data, pca)
一旦咱們有了原始特徵的投影(紅色箭頭),就能更加容易的理解散點圖每一個數據點的相對位置。
在這個雙標圖中,哪些初始特徵與第一個主成分有強關聯?哪些初始特徵與第二個主成分相關聯?你觀察到的是否與以前獲得的 pca_results 圖相符?
在這個部分,你講選擇使用K-Means聚類算法或者是高斯混合模型聚類算法以發現數據中隱藏的客戶分類。而後,你將從簇中恢復一些特定的關鍵數據點,經過將它們轉換回原始的維度和規模,從而理解他們的含義。
使用K-Means聚類算法的優勢是什麼?使用高斯混合模型聚類算法的優勢是什麼?基於你如今對客戶數據的觀察結果,你選用了這兩個算法中的哪個,爲何?
回答:
針對不一樣狀況,有些問題你須要的聚類數目多是已知的。可是在聚類數目不做爲一個先驗知道的狀況下,咱們並不可以保證某個聚類的數目對這個數據是最優的,由於咱們對於數據的結構(若是存在的話)是不清楚的。可是,咱們能夠經過計算每個簇中點的輪廓係數來衡量聚類的質量。數據點的輪廓係數衡量了它與分配給他的簇的類似度,這個值範圍在-1(不類似)到1(類似)。平均輪廓係數爲咱們提供了一種簡單地度量聚類質量的方法。
在接下來的代碼單元中,你將實現下列功能:
reduced_data
上使用一個聚類算法,並將結果賦值到clusterer
,須要設置 random_state
使得結果能夠復現。clusterer.predict
預測reduced_data
中的每個點的簇,並將結果賦值到preds
。centers
。pca_samples
中的每個樣本點的類別並將結果賦值到sample_preds
。reduced_data
相對於preds
的輪廓係數。
score
並輸出結果。# TODO:在降維後的數據上使用你選擇的聚類算法
from sklearn.mixture import GaussianMixture
from sklearn.metrics import silhouette_score
for i in xrange(2,9):
clusterer = GaussianMixture(n_components=i,random_state=0)
clusterer.fit(reduced_data)
preds = clusterer.predict(reduced_data)
centers = clusterer.means_
sample_preds = clusterer.predict(pca_samples)
score = silhouette_score(reduced_data,preds)
print score
clusterer = GaussianMixture(n_components=2,random_state=0)
clusterer.fit(reduced_data)
# TODO:預測每個點的簇
preds = clusterer.predict(reduced_data)
# TODO:找到聚類中心
centers = clusterer.means_
# TODO:預測在每個轉換後的樣本點的類
sample_preds = clusterer.predict(pca_samples)
# TODO:計算選擇的類別的平均輪廓係數(mean silhouette coefficient)
score = silhouette_score(reduced_data,preds)
彙報你嘗試的不一樣的聚類數對應的輪廓係數。在這些當中哪個聚類的數目可以獲得最佳的輪廓係數?
回答:
一旦你選好了經過上面的評價函數獲得的算法的最佳聚類數目,你就可以經過使用下面的代碼塊可視化來獲得的結果。做爲實驗,你能夠試着調整你的聚類算法的聚類的數量來看一下不一樣的可視化結果。可是你提供的最終的可視化圖像必須和你選擇的最優聚類數目一致。
# 從已有的實現中展現聚類的結果
vs.cluster_results(reduced_data, preds, centers, pca_samples)
上面的可視化圖像中提供的每個聚類都有一箇中心點。這些中心(或者叫平均點)並非數據中真實存在的點,可是是全部預測在這個簇中的數據點的平均。對於建立客戶分類的問題,一個簇的中心對應於那個分類的平均用戶。由於這個數據如今進行了降維並縮放到必定的範圍,咱們能夠經過施加一個反向的轉換恢復這個點所表明的用戶的花費。
在下面的代碼單元中,你將實現下列的功能:
pca.inverse_transform
將centers
反向轉換,並將結果存儲在log_centers
中。np.log
的反函數np.exp
反向轉換log_centers
並將結果存儲到true_centers
中。# TODO:反向轉換中心點
log_centers = pca.inverse_transform(centers)
# TODO:對中心點作指數轉換
true_centers = np.exp(log_centers)
# 顯示真實的中心點
segments = ['Segment {}'.format(i) for i in range(0,len(centers))]
true_centers = pd.DataFrame(np.round(true_centers), columns = data.keys())
true_centers.index = segments
display(true_centers)
考慮上面的表明性數據點在每個產品類型的花費總數,你認爲這些客戶分類表明了哪類客戶?爲何?須要參考在項目最開始獲得的統計值來給出理由。
提示: 一個被分到'Cluster X'
的客戶最好被用 'Segment X'
中的特徵集來標識的企業類型表示。
回答:
Cluster 0更像是零售商,由於他們的中心點Segment 0的各項特徵值都是50%左右,低於平均值,沒有某個特徵特別高,而量又沒有特別大,比較符合零售商什麼都賣,可是入貨不算多的特色
Cluster 1更像是奶茶店,而且他們的中心點Segment 1的值牛奶和、雜物和清潔紙的量超過了75%並且超過了平均數,而其餘的數量較少,奶茶店牛奶和紙巾的消耗必然不少,因此更有多是奶茶店
# 顯示預測結果
for i, pred in enumerate(sample_preds):
print "Sample point", i, "predicted to be in Cluster", pred
回答:
在最後一部分中,你要學習如何使用已經被分類的數據。首先,你要考慮不一樣組的客戶客戶分類,針對不一樣的派送策略受到的影響會有什麼不一樣。其次,你要考慮到,每個客戶都被打上了標籤(客戶屬於哪個分類)能夠給客戶數據提供一個多一個特徵。最後,你會把客戶分類與一個數據中的隱藏變量作比較,看一下這個分類是否辨識了特定的關係。
回答:
經過聚類技術,咱們可以將原有的沒有標記的數據集中的附加結構分析出來。由於每個客戶都有一個最佳的劃分(取決於你選擇使用的聚類算法),咱們能夠把用戶分類做爲數據的一個工程特徵。假設批發商最近迎來十位新顧客,而且他已經爲每位顧客每一個產品類別年度採購額進行了預估。進行了這些估算以後,批發商該如何運用它的預估和非監督學習的結果來對這十個新的客戶進行更好的預測?
提示:在下面的代碼單元中,咱們提供了一個已經作好聚類的數據(聚類結果爲數據中的cluster屬性),咱們將在這個數據集上作一個小實驗。嘗試運行下面的代碼看看咱們嘗試預測‘Region’的時候,若是存在聚類特徵'cluster'與不存在相比對最終的得分會有什麼影響?這對你有什麼啓發?
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
# 讀取包含聚類結果的數據
cluster_data = pd.read_csv("cluster.csv")
y = cluster_data['Region']
X = cluster_data.drop(['Region'], axis = 1)
# 劃分訓練集測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=24)
clf = RandomForestClassifier(random_state=24)
clf.fit(X_train, y_train)
print "使用cluster特徵的得分", clf.score(X_test, y_test)
# 移除cluster特徵
X_train = X_train.copy()
X_train.drop(['cluster'], axis=1, inplace=True)
X_test = X_test.copy()
X_test.drop(['cluster'], axis=1, inplace=True)
clf.fit(X_train, y_train)
print "不使用cluster特徵的得分", clf.score(X_test, y_test)
回答:
在這個項目的開始,咱們討論了從數據集中移除'Channel'
和'Region'
特徵,這樣在分析過程當中咱們就會着重分析用戶產品類別。經過從新引入Channel
這個特徵到數據集中,並施加和原來數據集一樣的PCA變換的時候咱們將可以發現數據集產生一個有趣的結構。
運行下面的代碼單元以查看哪個數據點在降維的空間中被標記爲'HoReCa'
(旅館/餐館/咖啡廳)或者'Retail'
。另外,你將發現樣本點在圖中被圈了出來,用以顯示他們的標籤。
# 根據‘Channel‘數據顯示聚類的結果
vs.channel_results(reduced_data, outliers, pca_samples)
你選擇的聚類算法和聚類點的數目,與內在的旅館/餐館/咖啡店和零售商的分佈相比,有足夠好嗎?根據這個分佈有沒有哪一個簇可以恰好劃分紅'零售商'或者是'旅館/飯店/咖啡館'?你以爲這個分類和前面你對於用戶分類的定義是一致的嗎?
回答:
歡迎掃碼關注,或搜索大數據與知識圖譜,按期分享大數據與知識圖譜相關知識點: