數據預處理
先手工生成一些數據,用來說明數據預處理的原理和方法
#導入numpy import numpy as np #導入畫圖工具 import matplotlib.pyplot as plt #導入數據集生成工具 from sklearn.datasets import make_blobs X,y = make_blobs(n_samples=40,centers=2,random_state=50,cluster_std=2) #用散點圖繪制數據點 plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.cool) plt.show()

【結果分析】
在使用make_blobs函數時,指定了樣本數量n_samples=40,分類centers=2,隨機狀態random_state=50,標注差cluster_std=2
1.使用StandardScaler預處理數據
原理:
將所有數據的特征值轉換為均值為0,方差為1的狀態——> 確保數據的“大小”一樣,更利於模型的訓練
#導入StandardScaler from sklearn.preprocessing import StandardScaler #使用StandardScaler進行數據預處理 X_1 = StandardScaler().fit_transform(X) #用散點圖繪制預處理的數據點 plt.scatter(X_1[:,0],X_1[:,1],c=y,cmap=plt.cm.cool) plt.show()

【結果分析】
以上兩圖,發現數據點的分布情況沒有什么不同,但xy軸發生了變化
現在,特征1的數值在-2,3之間
特征2的數值在-3,2之間
2.使用MinMaxScaler數據預處理
#導入MinMaxScaler from sklearn.preprocessing import MinMaxScaler #使用MinMaxScaler進行數據預處理 X_2 = MinMaxScaler().fit_transform(X) #用散點圖繪制預處理的數據點 plt.scatter(X_2[:,0],X_2[:,1],c=y,cmap=plt.cm.cool) plt.show()

【結果分析】
所有數據的兩個特征值都被轉換到0-1之間——> 訓練速度更快,准確率提高
3.使用RobustScaler數據預處理
和StandardScaler近似
使用中位數和四分位數,直接把一些異常值踢出
#導入RobustScaler from sklearn.preprocessing import RobustScaler #使用RobustScaler進行數據預處理 X_3 = RobustScaler().fit_transform(X) #用散點圖繪制預處理的數據點 plt.scatter(X_3[:,0],X_3[:,1],c=y,cmap=plt.cm.cool) plt.show()

【結果分析】
特征1控制在-1.5~2
特征2控制在-2~1.5
4.使用Normalizer數據預處理
將所有樣本的特征向量轉化為歐幾里得距離為1
即,將數據的分布變成一個半徑為1的圓(或球)
通常在我們只想保留數據特征向量的方向,而忽略其數值的時候使用
#導入Normalizer from sklearn.preprocessing import Normalizer #使用Normalizer進行數據預處理 X_4 = Normalizer().fit_transform(X) #用散點圖繪制預處理的數據點 plt.scatter(X_4[:,0],X_4[:,1],c=y,cmap=plt.cm.cool) plt.show()

通過數據預處理提高模型的准確率
#導入紅酒數據集 from sklearn.datasets import load_wine #導入MLP神經網絡 from sklearn.neural_network import MLPClassifier #導入數據集拆分工具 from sklearn.model_selection import train_test_split #建立訓練集和測試集 wine = load_wine() X_train,X_test,y_train,y_test = train_test_split(wine.data,wine.target,random_state=62) #打印數據形態 print(X_train.shape,X_test.shape)

【結果分析】
已成功將數據集拆分為訓練集和測試集。訓練集樣本數量為133個,測試集樣本數量為45個
1.用訓練集訓練一個MLP神經網絡,看看在測試集中的得分
#設定MLP神經網絡的參數 mlp = MLPClassifier(hidden_layer_sizes=[100,100],max_iter=400,random_state=62) #使用MLP擬合數據 mlp.fit(X_train,y_train) #打印得分 print(mlp.score(X_test,y_test))
0.9333333333333333
2.預處理數據
#使用MinMaxScaler進行數據預處理 scaler = MinMaxScaler() scaler.fit(X_train) X_train_pp = scaler.transform(X_train) X_test_pp = scaler.transform(X_test) #重新訓練模型 mlp.fit(X_train_pp,y_train) #得分 print(mlp.score(X_test_pp,y_test))
1.0
【結果分析】
經過數據預處理后,神經網絡進行了完美分類
數據降維
數據集中,樣本往往有很多特征,這些特征都是同樣重要的嗎?
是否有一些關鍵特征對預測的結果起着決定性的作用呢?
1.PCA主成分分析原理



經過這樣的處理后,數據集從一個散點組成的面變成了一條直線,即從二維變成了以為,這就是 數據降維
這里用到的方法,即主成分分析法—— PCA
適用數據降維的情況:
- 超高維度數據
- 特征之間有非常強烈的相關性【比如,人口數據中,男性為1,女性為0,去掉其中任何一列,不會丟失任何信息,可以降維,以降低模型的復雜度】
對數據降維以便於進行可視化
#導入數據預處理工具 from sklearn.preprocessing import StandardScaler #對紅酒數據集預處理 scaler = StandardScaler() X = wine.data y = wine.target X_scaled = scaler.fit_transform(X) #打印處理后的數據集形態 print(X_scaled.shape)
(178, 13)
接下來導入PCA模塊,並對數據進行處理
注意:PCA主成分分析法屬於無監督學習算法,所以這里值對X_scaled進行了擬合,而並沒有涉及分類標簽y
#導入PCA from sklearn.decomposition import PCA #設置生成分數量為2以便可視化 pca = PCA(n_components=2) pca.fit(X_scaled) X_pca = pca.transform(X_scaled) #打印主成分提取后的數據形態 print(X_pca.shape)
(178, 2)
#將三個分類中的主成分提取出來 X0 = X_pca[wine.target==0] X1 = X_pca[wine.target==1] X2 = X_pca[wine.target==2] #繪制散點圖 plt.scatter(X0[:,0],X0[:,1],c='b',s=60,edgecolor='k') plt.scatter(X1[:,0],X1[:,1],c='g',s=60,edgecolor='k') plt.scatter(X2[:,0],X2[:,1],c='r',s=60,edgecolor='k') #設置圖注 plt.legend(wine.target_names,loc='best') plt.xlabel('component 1') plt.ylabel('component 2') plt.show()

【結果分析】
在之前的章節中,為了進行可視化,只能選取酒數據集的前兩個特征,而去掉了其余的11個特征
使用PCA將數據集的特征向量降至二維,從而輕松進行可視化處理,同時不會丟失太多信息
原始特征與PCA主成分之間的關系
酒的數據集中的13個原始特征與經過PCA降維處理后的兩個主成分是怎樣的關系?
#使用主成分繪制熱度圖 plt.matshow(pca.components_,cmap='plasma') #縱軸為主成分數 plt.yticks([0,1],['component 1','component 2']) plt.colorbar() #橫軸為原始特征數量 plt.xticks(range(len(wine.feature_names)),wine.feature_names,rotation=60,ha='left') plt.show()

【結果分析】
本圖中
,不同的顏色表示一個位於-0.5~0.4之間的數值,分別涉及了13個特征
如果某個特征對應的數字是正數,則說明它和主成分之間是正相關的關系,如果是負數,則相反

特征提取
由以上,可以得到:
我們通過對數據集原來的特征進行轉換,生成新的“特征”或者說“成分”,會比直接使用原始的特征效果更好
1.PCA主成分分析法用於特征提取
這次使用一個復雜一點的數據集——LFW人臉識別數據
#導入數據集獲取工具
from sklearn.datasets import fetch_lfw_people
#載入人臉數據集
faces = fetch_lfw_people(min_faces_per_person=20,resize=0.8)
image_shape = faces.images[0].shape
#將照片打印出來
fig,axes = plt.subplots(3,4,figsize=(12,9),subplot_kw={'xticks':(),'yticks':()})
for target,image,ax in zip(faces.target,faces.images,axes.ravel()):
ax.imshow(image,cmap=plt.cm.gray)
ax.set_title(faces.target_names[target])
plt.show()

接下來,再未經處理的情況下,嘗試訓練一個神經網絡:
#導入神經網絡 from sklearn.neural_network import MLPClassifier #對數據集拆分 X_train,X_test,y_train,y_test = train_test_split(faces.data/255,faces.target,random_state=62) #訓練神經網絡 mlp=MLPClassifier(hidden_layer_sizes=[100,100],random_state=62,max_iter=400) mlp.fit(X_train,y_train) print(mlp.score(X_test,y_test))
0.7477064220183486
【結果分析】
在使用2個節點數為100的隱藏層時,神經網絡的識別准確率只有0.74
2.使用一些方法來提升模型的表現
A.PCA中的數據白化功能
雖然每個人的面部特征由很大差異,但從像素級別觀察圖像,差異並不大
且相鄰的像素之間有很大的相關性,這樣一來,基本特征的輸入就是冗余的了,白化的目的就是未了降低冗余性
所以,白化的過程會讓樣本特征之間的相關度降低,且所有特征具有相同的方差
#使用白化功能處理人臉數據 pca = PCA(whiten=True,n_components=0.9,random_state=62).fit(X_train) X_train_whiten = pca.transform(X_train) X_test_whiten = pca.transform(X_test) #打印白化后數據形態 print(X_train_whiten.shape)
(1306, 99)
【結果分析】
這里我們要求保留原始特征中90%的信息,所以n_components=0.9
可見,經過PCA白化處理后的數據成分為99個,遠遠小於原始特征數量
#使用白化后的數據訓練神經網絡 mlp.fit(X_train_whiten,y_train) print(mlp.score(X_test_whiten,y_test))
0.7293577981651376
【結果分析】
書上的得分分別是:神經網絡:0.52 PCA 0.57 ——> PCA的數據白化功能對於提高神經網絡的准確率是有一定幫助的
B.非負矩陣分解用於特征提取
NMF, 也是一種無監督學習算法
矩陣分解就是一個把矩陣拆解為n個矩陣的乘積
非負矩陣分解,就是原始的矩陣中所有的數值必須大於或等於0,當然分解之后的矩陣中數據也是大於或等於0的

#導入NMF from sklearn.decomposition import NMF nmf = NMF(n_components=105,random_state=62).fit(X_train) X_train_nmf = nmf.transform(X_train) X_test_nmf = nmf.transform(X_test) #打印NMF處理后的數據形態 print(X_train_nmf.shape)
(1306, 105)
【結果分析】
NMF的n_components參數不支持使用浮點數,只能設置為正的整型數
#使用NMF處理后的數據訓練神經網絡 mlp.fit(X_train_nmf,y_train) print(mlp.score(X_test_nmf,y_test))
0.7591743119266054
聚類算法
有監督學習——主要用於——> 分類和回歸
無監督學習——主要用於——> 聚類
分類是算法基於已有標簽的數據進行學習並對新數據進行分類
聚類是在完全沒有現有標簽的情況下,由算法“猜測”哪些數據像是應該“堆”在一起的,並且讓算法給不同“堆”里的數據貼上一個數字標簽
1.K均值算法

#導入數據集生成工具 from sklearn.datasets import make_blobs #生成分類數為1的數據集 blobs = make_blobs(random_state=1,centers=1) X_blobs = blobs[0] #繪制散點圖 plt.scatter(X_blobs[:,0],X_blobs[:,1],c='r',edgecolor='k') plt.show()

【結果分析】
這段代碼,主要是生成一坨沒有類別的數據點
make_blobs的centers參數為1,因此這些數據都屬於1類
使用K均值幫助這些數據進行聚類:
#導入KMeans工具 from sklearn.cluster import KMeans #要求KMeans將數據聚為3類 kmeans = KMeans(n_clusters=3) #擬合數據 kmeans.fit(X_blobs) #畫圖 x_min,x_max = X_blobs[:,0].min() -0.5,X_blobs[:,0].max() +0.5 y_min,y_max = X_blobs[:,1].min() -0.5,X_blobs[:,1].max() +0.5 xx,yy = np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02)) Z = kmeans.predict(np.c_[(xx.ravel(),yy.ravel())]) #將每個分類中的樣本分配不同的顏色 Z = Z.reshape(xx.shape) plt.figure(1) plt.imshow(Z,interpolation='nearest',extent=(xx.min(),xx.max(),yy.min(),yy.max()),cmap=plt.cm.summer,aspect='auto',origin='lower') plt.plot(X_blobs[:,0],X_blobs[:,1],'r.',markersize=5) #用藍色叉號表示聚類的中心 centroids = kmeans.cluster_centers_ plt.scatter(centroids[:,0],centroids[:,1],marker='x',s=150,linewidth=3,color='b',zorder=10) plt.xlim(x_min,x_max) plt.ylim(y_min,y_max) plt.xticks(()) plt.yticks(()) plt.show()

【結果分析】
n_clusters=3,所以K均值將數據點聚為3類
圖中的3個藍色X,代表了K均值對數據進行聚類的3個中心
那么K均值怎樣來表示這些聚類?
#打印KMeans進行聚類的標簽 print(kmeans.labels_)

【結果分析】
K均值對數據進行的聚類和分類有些類似,是用0、1、2三個數字來代表數據的類,並且存儲在 .labels_ 屬性中
局限性:
認為每個數據點到聚類中心的方向都是同等重要的——> 對於形狀復雜的數據集,K均值算法就不能很好工作
2.凝聚聚類算法

用圖像對凝聚算法的工作機制說明:
#導入dendrogram和ward工具 from scipy.cluster.hierarchy import dendrogram,ward #使用連線的方式可視化 linkage = ward(X_blobs) dendrogram(linkage) ax = plt.gca() plt.xlabel("sample index") plt.ylabel("cluster distance") plt.show()

【結果分析】
凝聚聚類算法是自下而上,不斷合並相似的聚類中心,以便讓類別變少
同時,每個聚類中心的距離也就越來越遠
這種逐級生成的聚類方法為:Hierarchy clustering
但,凝聚聚類算法也無法對“形狀復雜的數據進行正確的聚類
3.DBSCAN算法
基於密度的有噪聲應用空間聚類
通過對特征空間內的密度進行檢測,密度大的地方,它會認為是一個類,而密度較小的地方,它會認為是一個分界線
再用之前生成的數據集來展示一下DBSCAN的工作機制:
#導入DBSCAN from sklearn.cluster import DBSCAN db = DBSCAN() #使用DBSCAN擬合數據 clusters = db.fit_predict(X_blobs) #繪制散點圖 plt.scatter(X_blobs[:,0],X_blobs[:,1],c=clusters,cmap=plt.cm.cool,s=60,edgecolor='k') plt.xlabel("feature 0") plt.ylabel("feature 1") plt.show()

#打印聚類個數 print(clusters)

【結果分析】
-1 代表該數據是噪聲
中間深色的數據點密度相對較大,所以DBSCAN把它歸為一坨
而外圍的淺色數據點,DBSCAN認為根本不屬於任何一類,所以放在“噪聲”一類
eps參數,指考慮化入同一“坨”的樣本距離多遠
默認0.5
#設置DBSCAN參數eps=2 db_1 = DBSCAN(eps=2) #使用DBSCAN擬合數據 clusters_1 = db_1.fit_predict(X_blobs) #繪制散點圖 plt.scatter(X_blobs[:,0],X_blobs[:,1],c=clusters_1,cmap=plt.cm.cool,s=60,edgecolor='k') plt.xlabel("feature 0") plt.ylabel("feature 1") plt.show()

min_samples參數,指定再某個數據點周圍,被看成是聚類核心點的個數。越大,則核心數據點越少,噪聲就越多
默認是2
#設置DBSCAN的最小樣本數為20 db_2 = DBSCAN(min_samples=20) #使用DBSCAN擬合數據 clusters_2 = db_2.fit_predict(X_blobs) #繪制散點圖 plt.scatter(X_blobs[:,0],X_blobs[:,1],c=clusters_2,cmap=plt.cm.cool,s=60,edgecolor='k') plt.xlabel("feature 0") plt.ylabel("feature 1") plt.show()

【結果分析】
淺色的數據,也就是噪聲變多了
深色的數據,也就是聚類中被划為類別1的數據點少了

對於機器學習來說,合理有效地對數據進行表達是至關重要的
對於沒有分類標簽的數據來說,無監督學習的聚類算法可以幫助我們更好的理解數據集,並且為進一步訓練模型打好基礎
