1. 程式人生 > >Python資料科學手冊-第5章機器學習

Python資料科學手冊-第5章機器學習

文章目錄

機器學習的分類

  • 有監督學習是指對資料的若干特徵和若干標籤之間的關聯性進行建模的過程;只要模型被確定,就可以應用到新的未知資料上。可以分為分類與迴歸,分類的標籤時離散值,迴歸的標籤時連續值。
  • 無監督學習是指對不帶任何標籤的資料特徵進行建模,通常被看成是一種“讓資料自己介紹自己”的過程。包括聚類和降維,聚類演算法可以將資料分成不同的組別,而降維演算法追求用更簡潔的方式表示資料
  • 還有一種半監督學習方法,介於有監督學習和無監督學習之間,半監督學習通常可以在資料標籤不完整是使用

Scikit-Learn

Scikit-Learn的資料表示

  1. 資料表
    基本的資料表就是二維網格資料,其中每一行表示資料集中的每個樣本,而列表示構成每個樣本的相關特徵
  2. 特徵矩陣
    這個表格佈局通過二維陣列或矩陣的形式將資訊清晰的表示出來,所以我們通常把這類矩陣稱為特徵矩陣
  3. 目標陣列
    目標陣列一般是一位陣列,其長度就是樣本總數,通常都用一維的NumPy陣列或Pandas的Series表示,目標陣列可以是連續的數值型別,也可以是離散的型別

Scikit-Learn的評估器API

  1. API基礎
    Scikit-Learn的評估器API常用步驟:
    (1) 通過從Scikit-Learn中匯入適當的評估器類,選擇模型類
    (2) 用合適的數值對模型進行例項化,配置模型超引數
    (3) 整理資料
    (4) 呼叫模型例項的fit()方法對資料進行擬合
    (5) 對新資料應用模型:
  • 在有監督學習模型中,通常使用predict()方法預測資料的標籤
  • 在無監督學習模型中,通常使用transform()或predict()方法轉換或推斷資料的性質
  1. 有監督學習例項:簡單線性迴歸
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('seaborn-whitegrid')
fig,ax=plt.subplots(1,2,sharex='col',sharey='row',figsize=(16,8))
rng=np.random.RandomState(42)
x=10*rng.rand(50)
y=2*x-1+rng.randn(50)
ax[0].scatter(x,y)
#選取模型類
from sklearn.linear_model import LinearRegression
#選取模型超引數,fit_intercept=True設定是否想要擬合直線的截距
model=LinearRegression(fit_intercept=True)
#將資料整理成特徵矩陣和目標陣列,這裡需要將資料x整理成[n_samples,n_features]的形式
X=x[:,np.newaxis]
#用模型擬合數據
model.fit(X,y)
#所有通過fit方法獲得的模型引數都帶一條下劃線,下面兩個引數分別對直線的斜率和截距
display(model.coef_)
display(model.intercept_)
#預測新的資料
xfit=np.linspace(-1,11)
Xfit=xfit[:,np.newaxis]
yfit=model.predict(Xfit)
ax[1].scatter(x,y)
ax[1].plot(xfit,yfit)


3. 有監督的學習示例:鳶尾花資料分類

#匯入資料,構造資料集
import seaborn as sns
iris=sns.load_dataset('iris')
X_iris=iris.drop('species',axis=1)
y_iris=iris['species']
#將資料劃分為訓練集和測試集
from sklearn.cross_validation import train_test_split
Xtrain,Xtest,ytrain,ytest=train_test_split(X_iris,y_iris,random_state=1)
#匯入高斯樸素貝葉斯方法
from sklearn.naive_bayes import GaussianNB
model=GaussianNB()
model.fit(Xtrain,ytrain)
y_model=model.predict(Xtest)
#用accuracy_score工具驗證模型預測結果的準確性
from sklearn.metrics import accuracy_score
accuracy_score(ytest,y_model)

輸出:0.9736842105263158
4. 無監督學習示例:鳶尾花資料降維

#選擇模型
from sklearn.decomposition import PCA
#設定超引數
model=PCA(n_components=2)
#擬合數據
model.fit(X_iris)
#將資料轉換為二維
X_2D=model.transform(X_iris)
iris['PCA1']=X_2D[:,0]
iris['PCA2']=X_2D[:,1]
sns.lmplot("PCA1","PCA2",hue='species',data=iris,fit_reg=False,palette="Blues_d")


5. 無監督學習示例:鳶尾花資料聚類

#選擇高斯混合模型
from sklearn.mixture import GMM
model=GMM(n_components=3,covariance_type='full')
model.fit(X_iris)
y_gmm=model.predict(X_iris)
iris['cluster']=y_gmm
sns.lmplot("PCA1","PCA2",data=iris,hue='species',col='cluster',fit_reg=False,palette="muted");

應用:手寫數字探索

(1) 使用sklearn中介面載入資料並顯示

from sklearn.datasets import load_digits
digits=load_digits()
import matplotlib.pyplot as plt
fig,axes=plt.subplots(10,10,figsize=(8,8),subplot_kw={'xticks':[],'yticks':[]},gridspec_kw=dict(hspace=0.1,wspace=0.1))
for i,ax in enumerate(axes.flat):
    ax.imshow(digits.images[i],cmap='binary',interpolation='nearest')
    ax.text(0.05,0.05,str(digits.target[i]),color='green',transform=ax.transAxes)


(2) 每個數字的解析度是8*8所以每個樣本有64個特徵,視覺化很困難,所以要使用無監督學習的方法將維度降到二維,這裡使用的流形學習演算法中的Isomap演算法進行降維

from sklearn.manifold import Isomap
iso=Isomap(n_components=2)
iso.fit(digits.data)
data_projected=iso.transform(digits.data)
plt.scatter(data_projected[:,0],data_projected[:,1],c=digits.target,edgecolors='none',alpha=0.5,cmap=plt.cm.get_cmap('Spectral',10))
plt.colorbar(label='digit label',ticks=range(10))
plt.clim(-0.5,9.5);


(3) 詳見資料分為訓練集和測試集,然後用高斯貝葉斯模型來擬合

Xtrain,Xtest,ytrain,ytest=train_test_split(digits.data,digits.target,random_state=0)
model=GaussianNB()
model.fit(Xtrain,ytrain)
y_model=model.predict(Xtest)
accuracy_score(ytest,y_model)

輸出:0.8333333333333334
這是就可以使用混淆矩陣進行分析模型在哪裡表現不好,混淆矩陣可以通過sklearn計算

from sklearn.metrics import confusion_matrix
mat=confusion_matrix(ytest,y_model)
sns.heatmap(mat,square=True,annot=True,cbar=False)
plt.xlabel('predicted value')
plt.ylabel('true value');


也可以將錯誤的樣本顯示出來,如綠色表示正確,藍色表示錯誤

fig,axes=plt.subplots(10,10,figsize=(8,8),subplot_kw={'xticks':[],'yticks':[]},gridspec_kw=dict(hspace=0.1,wspace=0.1))
test_images=Xtest.reshape(-1,8,8)
for i,ax in enumerate(axes.flat):
    ax.imshow(test_images[i],cmap='binary',interpolation='nearest')
    ax.text(0.05,0.05,str(y_model[i]),color='green' if (ytest[i]==y_model[i]) else 'blue',transform=ax.transAxes)

超引數與模型驗證

模型驗證

  1. 錯誤的模型驗證方法
    使用同一資料訓練和評估模型,在理想情況準確率很高,但這並不能說明模型對新的資料的擬合程度
from sklearn.datasets import load_iris
iris=load_iris()
x=iris.data
y=iris.target
from sklearn.neighbors import KNeighborsClassifier
mode=KNeighborsClassifier(n_neighbors=1)
model.fit(x,y)
y_model=model.predict(x)
accuracy_score(y,y_model)

輸出:0.96
2. 模型驗證正確方法:留出集
將資料集留出一部分作為驗證集,使用驗證集來檢驗模型效能

x1,x2,y1,y2=train_test_split(x,y,random_state=0,train_size=0.5)
model.fit(x1,y1)
y2_model=model.predict(x2)
accuracy_score(y2,y2_model)

輸出:0.9466666666666667
3. 交叉驗證
使用留出集有一個缺點,就是模型失去了一部分訓練機會,尤其是在訓練資料集規模比較小的時候,所以就讓資料的每個子集既是訓練集,又是訓練集

y2_model=model.fit(x1,y1).predict(x2)
y1_model=model.fit(x2,y2).predict(x1)
accuracy_score(y1,y1_model),accuracy_score(y2,y2_model)

輸出:(0.9733333333333334, 0.9466666666666667)
將資料集分成兩個子集叫作兩輪交叉驗證,也可以擴充套件這個概念,例如五輪交叉驗證

from sklearn.cross_validation import cross_val_score
cross_val_score(model,x,y,cv=5)

輸出:array([0.93333333, 0.96666667, 0.93333333, 0.93333333, 1. ])
還有一些其他的交叉驗證方法如LOO交叉驗證,每次只保留一個樣本做測試

from sklearn.cross_validation import LeaveOneOut
cross_val_score(model,x,y,cv=LeaveOneOut(len(x)))

輸出:
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 0., 1., 1., 1., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
這時計算所有實驗準確率的均值就可以得到模型的預測準確性了

選擇最優模型

  1. 偏差和方差的平衡

    上面左圖這樣的模型被認為欠擬合,它希望找一條直線去擬合數據,但是資料本質上比直線要複雜,這樣的模型也叫作高偏差
    上面右圖這樣的模型被認為過擬合,它十分準確的描述了訓練資料,當過多的學習了資料的噪音,這樣的模型也叫作高方差

    通過計算不同模型複雜度(例如多項式的次數)下的訓練分數和驗證分數來找到最好的模型
  2. Scikit-Learn驗證曲線
# 構造資料
import numpy as np
def make_data(N=30, err=0.8, rseed=1):
    # randomly sample the data
    rng = np.random.RandomState(rseed)
    X = rng.rand(N, 1) ** 2
    y = 10 - 1. / (X.ravel() + 0.1)
    if err > 0:
        y += err * rng.randn(N)
    return X, y
# 構建帶多項式前處理器的簡單線性迴歸模型
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline

def PolynomialRegression(degree=2, **kwargs):
    return make_pipeline(PolynomialFeatures(degree),
                         LinearRegression(**kwargs));
# 將不同次數的多項式擬合曲線畫出來
X, y = make_data()
xfit = np.linspace(-0.1, 1.0, 1000)[:, None]
model1 = PolynomialRegression(1).fit(X, y)
model20 = PolynomialRegression(20).fit(X, y)

fig, ax = plt.subplots(1, 2, figsize=(16, 6))
fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)

ax[0].scatter(X.ravel(), y, s=40)
ax[0].plot(xfit.ravel(), model1.predict(xfit), color='gray')
ax[0].axis([-0.1, 1.0, -2, 14])
ax[0].set_title('High-bias model: Underfits the data', size=14)

ax[1].scatter(X.ravel(), y, s=40)
ax[1].plot(xfit.ravel(), model20.predict(xfit), color='gray')
ax[1].axis([-0.1, 1.0, -2, 14])
ax[1].set_title('High-variance model: Overfits the data', size=14)


在這個例子中模型複雜性的關鍵就是多項式的次數,想要知道最好的次數去平衡偏差和方差就需要繪製驗證曲線,則可以使用sklearn中validation_curve函式實現

from sklearn.learning_curve import validation_curve
degree=np.arange(0,21)
train_score,val_score=validation_curve(PolynomialRegression(),X,y,'polynomialfeatures__degree',degree,cv=7)
plt.plot(degree,np.median(train_score,1),color='blue',label='training score')
plt.plot(degree,np.median(val_score,1),color='red',label='validation score')
plt.legend(loc='best')
plt.ylim(0,1)
plt.xlabel('degree')
plt.ylabel('score');


由驗證曲線可以看出最好的是三次多項式

學習曲線

影響模型複雜度的另一個重要因素是最優模型一般是收到訓練資料量的影響的,反應訓練集規模的訓練得分/驗證得分曲線被稱為學習曲線。
學習曲線的重要特徵就是,隨著訓練樣本數量的增加,分數會會收斂到定值,此時增加更多的訓練樣本也無濟於事

使用sklearn繪製學習曲線

from sklearn.learning_curve import learning_curve
fig,ax=plt.subplots(1,2,figsize=(16,6))
fig.subplots_adjust(left=0.0625,right=0.95,wspace=0.1)
for i,degree in enumerate([2,9]):
    N,train_lc,val_lc = learning_curve(PolynomialRegression(degree),X,y,cv=7,train_sizes=np.linspace(0.3,1,25))
    ax[i].plot(N,np.mean(train_lc,1),color='blue',label='training score')
    ax[i].plot(N,np.mean(val_lc,1),color='red',label='validation score')
    ax[i].hlines(np.mean([train_lc[-1],val_lc[-1]]),N[0],N[-1],color='gray',linestyle='dashed')
    ax[i].set_ylim(0, 1)
    ax[i].set_xlim(N[0], N[-1])
    ax[i].set_xlabel('training size')
    ax[i].set_ylabel('score')
    ax[i].set_title('degree = {0}'.format(degree), size=14)
    ax[i].legend(loc='best')

驗證實踐:網格搜尋

在實際工作中,模型通常會有多個得分轉折點,因此驗證曲線和學習曲線的圖形會從二位曲線變成多維曲面