Python機器學習筆記:sklearn庫的學習

戰爭熱誠發表於2018-12-29

  網上有很多關於sklearn的學習教程,大部分都是簡單的講清楚某一方面,其實最好的教程就是官方文件。

  官方文件地址:https://scikit-learn.org/stable/

(可是官方文件非常詳細,同時許多人對官方文件的理解和結構上都不能很好地把握,我也打算好好學習sklearn,這可能是機器學習的神器),下面先簡單介紹一下sklearn。

  自2007年釋出以來,scikit-learn已經成為Python重要的機器學習庫了,scikit-learn簡稱sklearn,支援包括分類,迴歸,降維和聚類四大機器學習演算法。還包括了特徵提取,資料處理和模型評估者三大模組。

  sklearn是Scipy的擴充套件,建立在Numpy和matplolib庫的基礎上。利用這幾大模組的優勢,可以大大的提高機器學習的效率。

  sklearn擁有著完善的文件,上手容易,具有著豐富的API,在學術界頗受歡迎。sklearn已經封裝了大量的機器學習演算法,包括LIBSVM和LIBINEAR。同時sklearn內建了大量資料集,節省了獲取和整理資料集的時間。

一,sklearn官方文件的內容和結構

1.1 sklearn官方文件的內容

  定義:針對經驗E和一系列的任務T和一定表現的衡量P,如果隨著經驗E的積累,針對定義好的任務T可以提高表現P,就說明機器具有學習能力。

1.2 sklearn官方文件結構

  由圖中,可以看到庫的演算法主要有四類:分類,迴歸,聚類,降維。其中:

  • 常用的迴歸:線性、決策樹、SVM、KNN ;整合迴歸:隨機森林、Adaboost、GradientBoosting、Bagging、ExtraTrees
  • 常用的分類:線性、決策樹、SVM、KNN,樸素貝葉斯;整合分類:隨機森林、Adaboost、GradientBoosting、Bagging、ExtraTrees
  • 常用聚類:k均值(K-means)、層次聚類(Hierarchical clustering)、DBSCAN
  • 常用降維:LinearDiscriminantAnalysis、PCA

這個流程圖代表:藍色圓圈是判斷條件,綠色方框是可以選擇的演算法,我們可以根據自己的資料特徵和任務目標去找一條自己的操作路線。

 二,sklearn的快速使用

  傳統的機器學習任務從開始到建模的一般流程就是:獲取資料——》資料預處理——》訓練模型——》模型評估——》預測,分類。本次我們將根據傳統機器學習的流程,看看在每一步流程中都有哪些常用的函式以及他們的用法是怎麼樣的。那麼首先先看一個簡單的例子:

  鳶尾花識別是一個經典的機器學習分類問題,它的資料樣本中包括了4個特徵變數,1個類別變數,樣本總數為150。

  它的目標是為了根據花萼長度(sepal length)、花萼寬度(sepal width)、花瓣長度(petal length)、花瓣寬度(petal width)這四個特徵來識別出鳶尾花屬於山鳶尾(iris-setosa)、變色鳶尾(iris-versicolor)和維吉尼亞鳶尾(iris-virginica)中的哪一種。

# 引入資料集,sklearn包含眾多資料集
from sklearn import datasets
# 將資料分為測試集和訓練集
from sklearn.model_selection import train_test_split
# 利用鄰近點方式訓練資料
from sklearn.neighbors import KNeighborsClassifier

# 引入資料,本次匯入鳶尾花資料,iris資料包含4個特徵變數
iris = datasets.load_iris()
# 特徵變數
iris_X = iris.data
# print(iris_X)
print('特徵變數的長度',len(iris_X))
# 目標值
iris_y = iris.target
print('鳶尾花的目標值',iris_y)
# 利用train_test_split進行訓練集和測試機進行分開,test_size佔30%
X_train,X_test,y_train,y_test=train_test_split(iris_X,iris_y,test_size=0.3)
# 我們看到訓練資料的特徵值分為3類
# print(y_train)
'''
[1 1 0 2 0 0 0 2 2 2 1 0 2 0 2 1 0 1 0 2 0 1 0 0 2 1 2 0 0 1 0 0 1 0 0 0 0
 2 2 2 1 1 1 2 0 2 0 1 1 1 1 2 2 1 2 2 2 0 2 2 2 0 1 0 1 0 0 1 2 2 2 1 1 1
 2 0 0 1 0 2 1 2 0 1 2 2 2 1 2 1 0 0 1 0 0 1 1 1 0 2 1 1 0 2 2]
 '''
# 訓練資料
# 引入訓練方法
knn = KNeighborsClassifier()
# 進行填充測試資料進行訓練
knn.fit(X_train,y_train)

params = knn.get_params()
print(params)
'''
{'algorithm': 'auto', 'leaf_size': 30, 'metric': 'minkowski',
 'metric_params': None, 'n_jobs': None, 'n_neighbors': 5, 
 'p': 2, 'weights': 'uniform'}

'''

score = knn.score(X_test,y_test)
print("預測得分為:%s"%score)
'''
預測得分為:0.9555555555555556
[1 2 1 1 2 2 1 0 0 0 0 1 2 0 1 0 2 0 0 0 2 2 0 2 2 2 2 1 2 2 2 1 2 2 1 2 0
 2 1 2 1 1 0 2 1]
[1 2 1 1 2 2 1 0 0 0 0 1 2 0 1 0 2 0 0 0 1 2 0 2 2 2 2 1 1 2 2 1 2 2 1 2 0
 2 1 2 1 1 0 2 1]
'''

# 預測資料,預測特徵值
print(knn.predict(X_test))
'''
[0 2 2 2 2 0 0 0 0 2 2 0 2 0 2 1 2 0 2 1 0 2 1 0 1 2 2 0 2 1 0 2 1 1 2 0 2
 1 2 0 2 1 0 1 2]
'''
# 列印真實特徵值
print(y_test)
'''
[1 2 2 2 2 1 1 1 1 2 1 1 1 1 2 1 1 0 2 1 1 1 0 2 0 2 0 0 2 0 2 0 2 0 2 2 0
 2 2 0 1 0 2 0 0]

'''

  

  下面,我們開始一步步介紹、

1,獲取資料

1.1 匯入sklearn資料集

  sklearn中包含了大量的優質的資料集,在我們學習機器學習的過程中,我們可以使用這些資料集實現出不同的模型,從而提高你動手實踐能力,同時這個過程也可以加深對理論知識的理解和把握。除了引入資料之外,我們還可以通過load_sample_images()來引入圖片。

  首先,要使用sklearn中的資料集,必須匯入datasets模組。

from sklearn import datasets

  下面兩個圖中包含了大部分sklearn中的資料集,呼叫方式也圖中給出,

 

這裡我們使用iris的資料來舉個例子,表示匯出資料集:

iris = datasets.load_iris() # 匯入資料集
X = iris.data # 獲得其特徵向量
y = iris.target # 獲得樣本label

 

1.2 建立資料集

  我們除了可以使用sklearn自帶的資料集,還可以自己去建立訓練樣本,

具體用法可以參考: https://scikit-learn.org/stable/datasets/

 

 

  下面我們拿分類問題的樣本生成器舉例子:

from sklearn.datasets.samples_generator import make_classification

X, y = make_classification(n_samples=6, n_features=5, n_informative=2, 
    n_redundant=2, n_classes=2, n_clusters_per_class=2, scale=1.0, 
    random_state=20)

# n_samples:指定樣本數
# n_features:指定特徵數
# n_classes:指定幾分類
# random_state:隨機種子,使得隨機狀可重

  測試如下:

>>> for x_,y_ in zip(X,y):
    print(y_,end=': ')
    print(x_)

    
0: [-0.6600737  -0.0558978   0.82286793  1.1003977  -0.93493796]
1: [ 0.4113583   0.06249216 -0.90760075 -1.41296696  2.059838  ]
1: [ 1.52452016 -0.01867812  0.20900899  1.34422289 -1.61299022]
0: [-1.25725859  0.02347952 -0.28764782 -1.32091378 -0.88549315]
0: [-3.28323172  0.03899168 -0.43251277 -2.86249859 -1.10457948]
1: [ 1.68841011  0.06754955 -1.02805579 -0.83132182  0.93286635]

 

1.2.1  用sklearn.datasets.make_blobs來生成資料

  scikit中的make_blobs方法常被用來生成聚類演算法的測試資料,直觀地說,make_blobs會根據使用者指定的特徵數量,中心點數量,範圍等來生成幾類資料,這些資料可用於測試聚類演算法的效果。

sklearn.datasets.make_blobs(n_samples=100, n_features=2, centers=3, 
cluster_std=1.0, center_box=(-10.0, 10.0), shuffle=True,
 random_state=None)[source]

  輸入:

  • n_samples表示產生多少個資料
  • n_features表示資料是幾維
  • centers表示資料點中心,可以輸入int數字,代表有多少箇中心,也可以輸入幾個座標(fixed center locations)
  • cluster_std表示分佈的標準差

  返回值:

  • X,[n_samples, n_features]形狀的陣列,代表產生的樣本
  • y,[n_samples]形狀的陣列,代表每個點的標籤(類別)

 例子(生成三類資料用於聚類(100個樣本,每個樣本2個特徵)):

from sklearn.datasets import make_blobs
from matplotlib import pyplot

data,label = make_blobs(n_samples=100,n_features=2,centers=5)

# 繪製樣本顯示
pyplot.scatter(data[:,0],data[:,1],c=label)
pyplot.show()

  結果:

 為每個類別設定不同的方差,只需要在上述程式碼中加入cluster_std引數即可:

import matplotlib.pylab as plt
from sklearn.datasets import make_blobs

# 每個樣本有幾個屬性或者特徵
n_features = 2

data,target = make_blobs(n_samples=100,n_features=2,centers=3,cluster_std=[1.0,2.0,3.0])
# 在2D圖中繪製樣本,每個樣本顏色不同
plt.scatter(data[:,0],data[:,1],c=target)
plt.show()

  

 

1.2.2  用sklearn.datasets.make_classification來生成資料

  通常用於分類演算法

sklearn.datasets.make_classification(n_samples=100, n_features=20, 
n_informative=2, n_redundant=2,n_repeated=0, n_classes=2, 
n_clusters_per_class=2, weights=None,flip_y=0.01, class_sep=1.0,
 hypercube=True,shift=0.0, scale=1.0, shuffle=True, random_state=None)

 輸入: 

n_features :特徵個數= n_informative() + n_redundant + n_repeated
n_informative:多資訊特徵的個數
n_redundant:冗餘資訊,informative特徵的隨機線性組合
n_repeated :重複資訊,隨機提取n_informative和n_redundant 特徵
n_classes:分類類別
n_clusters_per_class :某一個類別是由幾個cluster構成的

1.2.3  用sklearn.datasets.make_gaussian和make_hastie_10_2來生成資料

sklearn.datasets.make_gaussian_quantiles(mean=None, cov=1.0, n_samples=100,
 n_features=2, n_classes=3,shuffle=True, random_state=None)

  利用高斯分位點區分不同資料

sklearn.datasets.make_hastie_10_2(n_samples=12000, random_state=None)

  利用Hastie演算法,生成二分類資料

import matplotlib.pyplot as plt
 
from sklearn.datasets import make_classification
from sklearn.datasets import make_blobs
from sklearn.datasets import make_gaussian_quantiles
from sklearn.datasets import make_hastie_10_2
 
plt.figure(figsize=(8, 8))
plt.subplots_adjust(bottom=.05, top=.9, left=.05, right=.95)
 
plt.subplot(421)
plt.title("One informative feature, one cluster per class", fontsize='small')
X1, Y1 = make_classification(n_samples=1000,n_features=2, n_redundant=0, n_informative=1,
                             n_clusters_per_class=1)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(422)
plt.title("Two informative features, one cluster per class", fontsize='small')
X1, Y1 = make_classification(n_samples=1000,n_features=2, n_redundant=0, n_informative=2,
                             n_clusters_per_class=1)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(423)
plt.title("Two informative features, two clusters per class", fontsize='small')
X2, Y2 = make_classification(n_samples=1000,n_features=2, n_redundant=0, n_informative=2)
plt.scatter(X2[:, 0], X2[:, 1], marker='o', c=Y2)
 
 
plt.subplot(424)
plt.title("Multi-class, two informative features, one cluster",
          fontsize='small')
X1, Y1 = make_classification(n_samples=1000,n_features=2, n_redundant=0, n_informative=2,
                             n_clusters_per_class=1, n_classes=3)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(425)
plt.title("Three blobs", fontsize='small')
X1, Y1 = make_blobs(n_samples=1000,n_features=2, centers=3)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(426)
plt.title("Gaussian divided into four quantiles", fontsize='small')
X1, Y1 = make_gaussian_quantiles(n_samples=1000,n_features=2, n_classes=4)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(427)
plt.title("hastie data ", fontsize='small')
X1, Y1 = make_hastie_10_2(n_samples=1000)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
plt.show()

  結果:

1.2.4  用sklearn.datasets.make_circles和make_moons來生成資料

   生成環線資料

sklearn.datasets.make_circles(n_samples=100, shuffle=True, noise=None, 
random_state=None, factor=0.8)

  factor:外環和內環的尺度因子<1

sklearn.datasets.make_moons(n_samples=100, shuffle=True, noise=None, 
random_state=None)

  生成半環圖

from sklearn.datasets import make_circles
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
import numpy as np
 
fig=plt.figure(1)
x1,y1=make_circles(n_samples=1000,factor=0.5,noise=0.1)
plt.subplot(121)
plt.title('make_circles function example')
plt.scatter(x1[:,0],x1[:,1],marker='o',c=y1)
 
plt.subplot(122)
x1,y1=make_moons(n_samples=1000,noise=0.1)
plt.title('make_moons function example')
plt.scatter(x1[:,0],x1[:,1],marker='o',c=y1)
plt.show()

  結果:

 

2,資料預處理

   資料預處理階段是機器學習中不可缺少的一環,它會使得資料更加有效的被模型或者評估器識別。下面我們來看一下sklearn中有哪些平時我們常用的函式:

from sklearn import preprocessing

  為了使得訓練資料的標準化規則與測試資料的標準化規則同步,preprocessing中提供了很多的Scaler:

  • StandardScaler
  • MaxAbsScaler
  • MinMaxScaler
  • RobustScaler
  • Normalizer
  • 等其他預處理操作

  對應的有直接的函式使用:scale(),maxabs_scale(),minmax_scale(),robust_scale(),normaizer()

sklearn.preprocessing.scale(X)

 

2.1 資料標準化

  標準化:在機器學習中,我們可能要處理不同種類的資料,例如,音訊和圖片上的畫素值,這些資料可能是高緯度的,資料標準化後會使得每個特徵中的數值平均變為0(將每個特徵的值都減掉原始資料中該特徵的平均),標準差變為1,這個方法被廣泛的使用在許多機器學習演算法中(例如:支援向量機,邏輯迴歸和類神經網路)。

  StandardScaler計算訓練集的平均值和標準差,以便測試資料及使用相同的變換。

  變換後各維特徵有0均值,單位方差,也叫z-score規範化(零均值規範化),計算方式是將特徵值減去均值,除以標準差。

fit

  用於計算訓練資料的均值和方差,後面就會用均值和方差來轉換訓練資料

fit_transform

  不僅計算訓練資料的均值和方差,還會基於計算出來的均值和方差來轉換訓練資料,從而把資料轉化成標準的正態分佈。

transform

  很顯然,它只是進行轉換,只是把訓練資料轉換成標準的正態分佈。(一般會把train和test集放在一起做標準化,或者在train集上做標準化後,用同樣的標準化器去標準化test集,此時可以使用scaler)。

data = [[0, 0], [0, 0], [1, 1], [1, 1]]
# 1. 基於mean和std的標準化
scaler = preprocessing.StandardScaler().fit(train_data)
scaler.transform(train_data)
scaler.transform(test_data)

 

  一般來說先使用fit:

scaler = preocessing.StandardScaler().fit(X)

  這一步可以計算得到scaler,scaler裡面存的有計算出來的均值和方差。

  再使用transform

scaler.transform(X)

  這一步再用scaler中的均值和方差來轉換X,使X標準化。

  最後,在預測的時候,也要對資料做同樣的標準化處理,即也要用上面的scaler中的均值和方差來對預測時候的特徵進行標準化。

  注意:測試資料和預測資料的標準化的方式要和訓練資料標準化的方式一樣,必須使用同一個scaler來進行transform

2.2 最小-最大規範化

  最小最大規範化對原始資料進行線性變換,變換到[0,1]區間(也可以是其他固定最小最大值的區間)。

# 2. 將每個特徵值歸一化到一個固定範圍
scaler = preprocessing.MinMaxScaler(feature_range=(0, 1)).fit(train_data)
scaler.transform(train_data)
scaler.transform(test_data)
#feature_range: 定義歸一化範圍,注用()括起來

  

2.3 正則化(normalize)

   當你想要計算兩個樣本的相似度時必不可少的一個操作,就是正則化。其思想是:首先求出樣本的p範數,然後該樣本的所有元素都要除以該範數,這樣最終使得每個樣本的範數都是1。規範化(Normalization)是將不同變化範圍的值對映到相同的固定範圍,常見的是[0,1],也成為歸一化。

  如下例子,將每個樣本變換成unit norm。

>>> X = [[ 1., -1.,  2.],
...      [ 2.,  0.,  0.],
...      [ 0.,  1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')

>>> X_normalized                                      
array([[ 0.40..., -0.40...,  0.81...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 0.  ...,  0.70..., -0.70...]])

  我們可以發現對於每一個樣本都有0.4^2+0.4^2+0.81^2=1。這就是L2 norm,變換後每個樣本的各維特徵的平方和為1.類似的,L1 norm則是變換後每個樣本的各維特徵的絕對值之和為1.還有max norm,則是將每個樣本的各維特徵除以該樣本各維特徵的最大值,

  在度量樣本之間相似性時,如果使用的是二次型kernel,則需要做Normalization。

 

2.4 one-hot編碼

  one-hot編碼是一種對離散特徵值的編碼方式,在LR模型中常用到,用於給線性模型增加非線效能力。

data = [[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]]
encoder = preprocessing.OneHotEncoder().fit(data)
enc.transform(data).toarray()

  

2.5 特徵二值化(Binarization)

  給定閾值,將特徵轉換為0/1.

binarizer = sklearn.preprocessing.Binarizer(threshold=1.1)

binarizer.transform(X)

  

2.6 類別特徵編碼

  有時候特徵時類別型的,而一些演算法的輸入必須是數值型,此時需要對其編碼,

enc = preprocessing.OneHotEncoder()
enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
enc.transform([[0, 1, 3]]).toarray()  #array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])

  上面這個例子,第一維特徵有兩種值0和1,用兩位去編碼。第二維用三位,第三維用四位。

2.7 標籤編碼(Label encoding)

le = sklearn.preprocessing.LabelEncoder()  
le.fit([1, 2, 2, 6]) 
le.transform([1, 1, 2, 6])  #array([0, 0, 1, 2]) 
#非數值型轉化為數值型
le.fit(["paris", "paris", "tokyo", "amsterdam"])
le.transform(["tokyo", "tokyo", "paris"])  #array([2, 2, 1])

  

3,資料集拆分

  在得到訓練資料集時,通常我們經常會把訓練資料進一步拆分成訓練集和驗證集,這樣有助於我們模型引數的選取。

  train_test_split是交叉驗證中常用的函式,功能是從樣本中隨機的按比例選取train datatestdata,形式為:

X_train,X_test, y_train, y_test =

cross_validation.train_test_split(train_data,train_target,test_size=0.4, random_state=0)

  

引數解釋

  • train_data:所要劃分的樣本特徵集
  • train_target:所要劃分的樣本結果
  • test_size:樣本佔比,如果是整數的話就是樣本的數量
  • random_state:是隨機數的種子。
  • 隨機數種子:其實就是該組隨機數的編號,在需要重複試驗的時候,保證得到一組一樣的隨機數。比如你每次都填1其他引數一樣的情況下你得到的隨機陣列是一樣的。但填0或不填,每次都會不一樣。
  • 隨機數的產生取決於種子,隨機數和種子之間的關係遵從以下兩個規則:
  • 種子不同,產生不同的隨機數;種子相同,即使例項不同也產生相同的隨機數。

引數說明

 

 示例

# 作用:將資料集劃分為 訓練集和測試集
# 格式:train_test_split(*arrays, **options)
from sklearn.mode_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
"""
引數
---
arrays:樣本陣列,包含特徵向量和標籤

test_size:
  float-獲得多大比重的測試樣本 (預設:0.25)
  int - 獲得多少個測試樣本

train_size: 同test_size

random_state:
  int - 隨機種子(種子固定,實驗可復現)
  
shuffle - 是否在分割之前對資料進行洗牌(預設True)

返回
---
分割後的列表,長度=2*len(arrays), 
  (train-test split)
"""

  

拆分引數遇到的問題及其解決方法

  匯入模組

from sklearn.cross_validation import cross_val_score

  則會報錯,程式碼如下:

    from sklearn.cross_validation import cross_val_score
ModuleNotFoundError: No module named 'sklearn.cross_validation'

  解決方法:

from sklearn.model_selection import cross_val_score

  

4,定義模型

  在這一步我們首先要分析自己資料的型別,明白自己要用什麼模型來做,然後我們就可以在sklearn中定義模型了,sklearn為所有模型提供了非常相似的介面,這樣使得我們可以更加快速的熟悉所有模型的用法,在這之前,我們先來看看模型的常用屬性和功能。

# 擬合模型
model.fit(X_train, y_train)
# 模型預測
model.predict(X_test)

# 獲得這個模型的引數
model.get_params()
# 為模型進行打分
model.score(data_X, data_y) # 線性迴歸:R square; 分類問題: acc

  

4.1 線性迴歸

 

from sklearn.linear_model import LinearRegression
# 定義線性迴歸模型
model = LinearRegression(fit_intercept=True, normalize=False, 
    copy_X=True, n_jobs=1)

"""
引數
---
    fit_intercept:是否計算截距。False-模型沒有截距
    normalize: 當fit_intercept設定為False時,該引數將被忽略。 如果為真,
則迴歸前的迴歸係數X將通過減去平均值併除以l2-範數而歸一化。
     n_jobs:指定執行緒數
"""

  

4.2 邏輯迴歸LR

from sklearn.linear_model import LogisticRegression
# 定義邏輯迴歸模型
model = LogisticRegression(penalty=’l2’, dual=False, tol=0.0001, C=1.0, 
    fit_intercept=True, intercept_scaling=1, class_weight=None, 
    random_state=None, solver=’liblinear’, max_iter=100, multi_class=’ovr’, 
    verbose=0, warm_start=False, n_jobs=1)

"""引數
---
    penalty:使用指定正則化項(預設:l2)
    dual: n_samples > n_features取False(預設)
    C:正則化強度的反,值越小正則化強度越大
    n_jobs: 指定執行緒數
    random_state:隨機數生成器
    fit_intercept: 是否需要常量
"""

  

4.3 樸素貝葉斯演算法NB(Naive Bayes)

from sklearn import naive_bayes
model = naive_bayes.GaussianNB() # 高斯貝葉斯
model = naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
model = naive_bayes.BernoulliNB(alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None)
"""
文字分類問題常用MultinomialNB
引數
---
    alpha:平滑引數
    fit_prior:是否要學習類的先驗概率;false-使用統一的先驗概率
    class_prior: 是否指定類的先驗概率;若指定則不能根據引數調整
    binarize: 二值化的閾值,若為None,則假設輸入由二進位制向量組成
"""

  

 4.4 決策樹DT

from sklearn import tree 
model = tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None, 
    min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, 
    max_features=None, random_state=None, max_leaf_nodes=None, 
    min_impurity_decrease=0.0, min_impurity_split=None,
     class_weight=None, presort=False)
"""引數
---
    criterion :特徵選擇準則gini/entropy
    max_depth:樹的最大深度,None-儘量下分
    min_samples_split:分裂內部節點,所需要的最小樣本樹
    min_samples_leaf:葉子節點所需要的最小樣本數
    max_features: 尋找最優分割點時的最大特徵數
    max_leaf_nodes:優先增長到最大葉子節點數
    min_impurity_decrease:如果這種分離導致雜質的減少大於或等於這個值,則節點將被拆分。
"""

  

4.5 支援向量機SVM

from sklearn.svm import SVC
model = SVC(C=1.0, kernel=’rbf’, gamma=’auto’)
"""引數
---
    C:誤差項的懲罰引數C
    gamma: 核相關係數。浮點數,If gamma is ‘auto’ then 1/n_features will be used instead.
"""

  

4.6 k近鄰演算法KNN

from sklearn import neighbors
#定義kNN分類模型
model = neighbors.KNeighborsClassifier(n_neighbors=5, n_jobs=1) # 分類
model = neighbors.KNeighborsRegressor(n_neighbors=5, n_jobs=1) # 迴歸
"""引數
---
    n_neighbors: 使用鄰居的數目
    n_jobs:並行任務數
"""

  

4.7 多層感知器(神經網路)

from sklearn.neural_network import MLPClassifier
# 定義多層感知機分類演算法
model = MLPClassifier(activation='relu', solver='adam', alpha=0.0001)
"""引數
---
    hidden_layer_sizes: 元祖
    activation:啟用函式
    solver :優化演算法{‘lbfgs’, ‘sgd’, ‘adam’}
    alpha:L2懲罰(正則化項)引數。
"""

 

5,模型評估與選擇

  評價指標針對不同的機器學習任務有不同的指標,同一任務也有不同側重點的評價指標。以下方法,sklearn中都在sklearn.metrics類下,務必記住那些指標適合分類,那些適合迴歸。

   機器學習常用的評估指標請參考博文:Python機器學習筆記:常用評估指標的前世今生

5.1 交叉驗證

交叉驗證cross_val_score的scoring引數

  • 分類:accuracy(準確率)、f1、f1_micro、f1_macro(這兩個用於多分類的f1_score)、precision(精確度)、recall(召回率)、roc_auc
  • 迴歸:neg_mean_squared_error(MSE、均方誤差)、r2
  • 聚類:adjusted_rand_score、completeness_score等 

 

from sklearn.model_selection import cross_val_score
cross_val_score(model, X, y=None, scoring=None, cv=None, n_jobs=1)
"""引數
---
    model:擬合資料的模型
    cv : k-fold
    scoring: 打分引數-‘accuracy’、‘f1’、‘precision’、‘recall’ 、‘roc_auc’、'neg_log_loss'等等
"""

 

(補充):交叉驗證的學習

  1,匯入k折交叉驗證模組

from sklearn.model_selection import cross_val_score

  2,交叉驗證的思想

  把某種意義下將原始資料(dataset)進行分組,一部分作為訓練集(train set),另一部分作為驗證集(validation set or test set),首先用訓練集對分類器進行訓練,再利用驗證集來測試訓練得到的模型(model),以此來作為評價分類器的效能指標。

  3,為什麼使用交叉驗證法

  • 交叉驗證用於評估模型的預測效能,尤其是訓練好的模型在新資料上的表現,可以在一定程式熵減少過擬合。
  • 交叉驗證還可以從有限的資料中獲取儘可能多的有效資訊

  4,主要有哪些方法

1,留出法(holdout cross validation)

  在機器學習任務中,拿到資料後,我們首先會將原始資料集分為三部分:訓練集,驗證集和測試集。

  訓練集用於訓練模型,驗證集用於模型的引數選擇配置,測試集對於模型來說是未知資料,用於評估模型的泛化能力。

  這個方法操作簡單,只需要隨機將原始資料分為三組即可。

  不過如果只做一次分割,它對訓練集,驗證集和測試機的樣本比例,還有分割後資料的分佈是否和原始資料集的分佈相同等因素比較敏感,不同的劃分會得到不同的最優模型,,而且分成三個集合後,用於訓練的資料更少了。於是又了2.k折交叉驗證(k-fold cross validation).

  下面例子,一共有150條資料:

>>> import numpy as np
>>> from sklearn.model_selection import train_test_split
>>> from sklearn import datasets
>>> from sklearn import svm

>>> iris = datasets.load_iris()
>>> iris.data.shape, iris.target.shape
((150, 4), (150,))

  用train_test_split來隨機劃分資料集,其中40%用於測試集,有60條資料,60%為訓練集,有90條資料:

>>> X_train, X_test, y_train, y_test = train_test_split(
...     iris.data, iris.target, test_size=0.4, random_state=0)

>>> X_train.shape, y_train.shape
((90, 4), (90,))
>>> X_test.shape, y_test.shape
((60, 4), (60,))

  用train來訓練,用test來評價模型的分數。

>>> clf = svm.SVC(kernel='linear', C=1).fit(X_train, y_train)
>>> clf.score(X_test, y_test)                           
0.96...

  

2,2. k 折交叉驗證(k-fold cross validation)

 

   K折交叉驗證通過對k個不同分組訓練的結果進行平均來減少方差,因此模型的效能對資料的劃分就不那麼敏感。

  • 第一步,不重複抽樣將原始資料隨機分為 k 份。
  • 第二步,每一次挑選其中 1 份作為測試集,剩餘 k-1 份作為訓練集用於模型訓練。
  • 第三步,重複第二步 k 次,這樣每個子集都有一次機會作為測試集,其餘機會作為訓練集。
  • 在每個訓練集上訓練後得到一個模型,
  • 用這個模型在相應的測試集上測試,計算並儲存模型的評估指標,
  • 第四步,計算 k 組測試結果的平均值作為模型精度的估計,並作為當前 k 折交叉驗證下模型的效能指標。

K一般取10,資料量小的是,k可以設大一點,這樣訓練集佔整體比例就比較大,不過同時訓練的模型個數也增多。資料量大的時候,k可以設定小一點。當k=m的時候,即樣本總數,出現了留一法。

  舉例,這裡直接呼叫了cross_val_score,這裡用了5折交叉驗證

>>> from sklearn.model_selection import cross_val_score
>>> clf = svm.SVC(kernel='linear', C=1)
>>> scores = cross_val_score(clf, iris.data, iris.target, cv=5)
>>> scores                                              
array([ 0.96...,  1.  ...,  0.96...,  0.96...,  1.        ])

  得到最後平均分數為0.98,以及它的95%置信區間:

>>> print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
Accuracy: 0.98 (+/- 0.03)

  我們可以直接看一下K-Fold是怎麼樣劃分資料的:X有四個資料,把它分成2折,結構中最後一個集合是測試集,前面的是訓練集,每一行為1折:

>>> import numpy as np
>>> from sklearn.model_selection import KFold

>>> X = ["a", "b", "c", "d"]
>>> kf = KFold(n_splits=2)
>>> for train, test in kf.split(X):
...     print("%s %s" % (train, test))
[2 3] [0 1]
[0 1] [2 3]

  同樣的資料X,我們來看LeaveOneOut後是什麼樣子,那就是把它分成4折,結果中最後一個集合是測試集,只有一個元素,前面的是訓練集,每一行為1折:

>>> from sklearn.model_selection import LeaveOneOut

>>> X = [1, 2, 3, 4]
>>> loo = LeaveOneOut()
>>> for train, test in loo.split(X):
...     print("%s %s" % (train, test))
[1 2 3] [0]
[0 2 3] [1]
[0 1 3] [2]
[0 1 2] [3]

  

3,留一法(Leave one out cross validation)

  每次的測試集都只有一個樣本,要進行m次訓練和預測,這個方法用於訓練的資料只比整體資料集少一個樣本,因此最接近原始樣本的分佈。但是訓練複雜度增加了,因為模型的數量與原始資料樣本數量相同。一般在資料缺少時使用。

此外:

  • 多次 k 折交叉驗證再求均值,例如:10 次 10 折交叉驗證,以求更精確一點。
  • 劃分時有多種方法,例如對非平衡資料可以用分層取樣,就是在每一份子集中都保持和原始資料集相同的類別比例。
  • 模型訓練過程的所有步驟,包括模型選擇,特徵選擇等都是在單個摺疊 fold 中獨立執行的。

4,Bootstrapping

  通過自助取樣法,即在含有 m 個樣本的資料集中,每次隨機挑選一個樣本,再放回到資料集中,再隨機挑選一個樣本,這樣有放回地進行抽樣 m 次,組成了新的資料集作為訓練集。

  這裡會有重複多次的樣本,也會有一次都沒有出現的樣本,原資料集中大概有 36.8% 的樣本不會出現在新組資料集中。

  優點是訓練集的樣本總數和原資料集一樣都是 m,並且仍有約 1/3 的資料不被訓練而可以作為測試集。 
  缺點是這樣產生的訓練集的資料分佈和原資料集的不一樣了,會引入估計偏差。 
  (此種方法不是很常用,除非資料量真的很少)

 

5.2 檢驗曲線

  使用檢驗曲線,我們可以更加方便的改變模型引數,獲取模型表現。

from sklearn.model_selection import validation_curve
train_score, test_score = validation_curve(model, X, y, param_name, param_range, cv=None, scoring=None, n_jobs=1)
"""引數
---
    model:用於fit和predict的物件
    X, y: 訓練集的特徵和標籤
    param_name:將被改變的引數的名字
    param_range: 引數的改變範圍
    cv:k-fold
   
返回值
---
   train_score: 訓練集得分(array)
    test_score: 驗證集得分(array)
"""

  

5.3 分類模型

  • accuracy_score(準確率得分)是模型分類正確的資料除以樣本總數 【模型的score方法算的也是準確率】
accuracy_score(y_test,y_pre)
# 或者 model.score(x_test,y_test),大多模型都是有score方法的

  

  • classification_report中的各項得分的avg/total 是每一分類佔總數的比例加權算出來的
print(classification_report(y_test,y_log_pre))

             precision    recall  f1-score   support

          0       0.87      0.94      0.90       105
          1       0.91      0.79      0.85        73

avg / total       0.88      0.88      0.88       178

  

  • confusion_matrix(混淆矩陣),用來評估分類的準確性
>>> from sklearn.metrics import confusion_matrix
>>> y_true = [2, 0, 2, 2, 0, 1]
>>> y_pred = [0, 0, 2, 2, 0, 2]
>>> confusion_matrix(y_true, y_pred)
array([[2, 0, 0],
       [0, 0, 1],
       [1, 0, 2]])

  

  • precision_score(精確度)、recall_score(召回率)、f1_score(後者由前兩個推匯出的)
這三個不僅適合二分類,也適合多分類。只需要指出引數average=‘micro’/‘macro’/'weighted’

    macro:計算二分類metrics的均值,為每個類給出相同權重的分值。
當小類很重要時會出問題,因為該macro-averging方法是對效能的平均。
另一方面,該方法假設所有分類都是一樣重要的,因此macro-averaging
方法會對小類的效能影響很大

    micro: 給出了每個樣本類以及它對整個metrics的貢獻的pair(sample-
weight),而非對整個類的metrics求和,它會每個類的metrics上的權重及
因子進行求和,來計算整個份額。Micro-averaging方法在多標籤(multilabel)
問題中設定,包含多分類,此時,大類將被忽略

    weighted: 對於不均衡數量的類來說,計算二分類metrics的平均,
通過在每個類的score上進行加權實現
  • roc_curve(ROC曲線,用於二分類)

 

6 儲存模型

  最後,我們可以將我們訓練好的model儲存到本地,或者放到線上供使用者使用,那麼如何儲存訓練好的model呢?主要有下面兩種方式:

6.1 儲存為pickle檔案

import pickle

# 儲存模型
with open('model.pickle', 'wb') as f:
    pickle.dump(model, f)

# 讀取模型
with open('model.pickle', 'rb') as f:
    model = pickle.load(f)
model.predict(X_test)

  

6.2 sklearn自帶方法joblib

from sklearn.externals import joblib

# 儲存模型
joblib.dump(model, 'model.pickle')

#載入模型
model = joblib.load('model.pickle')

  

7,模型評分

  1,模型的score方法:最簡單的模型評估方法就是呼叫模型自己的方法:

# 預測
y_predict = knnClf.predict(x_test)
print("score on the testdata:",knnClf.score(x_test,y_test))

  2,sklearn的指標函式:庫提供的一些計算方法,常用的有classification_report方法

  3,sklearn也支援自己開發評價方法。

 

8,幾種交叉驗證(cross validation)方式的比較

  模型評價的目的:通過模型評價,我們知道當前訓練模型的好壞,泛化能力如何?從而知道是否可以應用在解決問題上,如果不行,那又是那些出了問題?

train_test_split

  在分類問題中,我們通常通過對訓練集進行triain_test_split,劃分出train 和test兩部分,其中train用來訓練模型,test用來評估模型,模型通過fit方法從train資料集中學習,然後呼叫score方法在test集上進行評估,打分;從分數上我們知道模型當前的訓練水平如何。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
import  matplotlib.pyplot as plt

cancer = load_breast_cancer()
X_train,X_test,y_train,y_test = train_test_split(cancer.data,cancer.target,random_state=0)

logreg = LogisticRegression().fit(X_train,y_train)
print("Test set score:{:.2f}".format(logreg.score(X_test,y_test)))

  結果:

Test set score:0.96

  然而這這方式只進行了一次劃分,資料結果具有偶然性,如果在某次劃分中,訓練集裡全是容易學習的資料,測試集裡全是複雜的資料,這樣的就會導致最終的結果不盡人意。

Standard Cross Validation

  針對上面通過train_test_split劃分,從而進行模型評估方式存在的弊端,提出Cross Validation交叉驗證。

  Cross Validation:進行多次train_test_split劃分;每次劃分時,在不同的資料集上進行訓練,測試評估,從而得到一個評價結果;如果是5折交叉驗證,意思就是在原始資料集上,進行五次劃分,每次劃分進行一次訓練,評估,最後得到5次劃分後的評估結果,一般在這幾次評估結果上取平均得到最後的評分,k-folf cross-validation ,其中K一般取5或10。

 

 程式碼:

from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
import  warnings

warnings.filterwarnings('ignore')

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    cancer.data , cancer.target, random_state=0
)

logreg = LogisticRegression()
# CV 預設是3折交叉驗證,可以修改cv=5,變為5折交叉驗證
scores = cross_val_score(logreg,cancer.data , cancer.target)

print("Cross validation scores:{}".format(scores))
print("Mean cross validation score:{:2f}".format(scores.mean()))

  結果:

Cross validation scores:[0.93684211 0.96842105 0.94179894]
Mean cross validation score:0.949021

交叉驗證的優點:

  • 原始採用的train_test_split方法,資料劃分具有偶然性;交叉驗證通過多次劃分,大大降低了這種由一次隨機劃分帶來的偶然性,同時通過多次劃分,多次訓練,模型也能遇到各種各樣的資料,從而提高其泛化能力
  • 與原始的train_test_split相比,對資料的使用效率更高,train_test_split,預設訓練集,測試集比例為3:1,而對交叉驗證來說,如果是5折交叉驗證,訓練集比測試集為4:1;10折交叉驗證訓練集比測試集為9:1.資料量越大,模型準確率越高!

交叉驗證的缺點:

這種簡答的交叉驗證方式,從上面的圖片可以看出來,每次劃分時對資料進行均分,設想一下,會不會存在一種情況:資料集有5類,抽取出來的也正好是按照類別劃分的5類,也就是說第一折全是0類,第二折全是1類,等等;這樣的結果就會導致,模型訓練時。沒有學習到測試集中資料的特點,從而導致模型得分很低,甚至為0,為避免這種情況,又出現了其他的各種交叉驗證方式。

Stratifid k-fold cross validation

  分層交叉驗證(Stratified k-fold cross validation):首先它屬於交叉驗證型別,分層的意思是說在每一折中都保持著原始資料中各個類別的比例關係,比如說:原始資料有3類,比例為1:2:1,採用3折分層交叉驗證,那麼劃分的3折中,每一折中的資料類別保持著1:2:1的比例,這樣的驗證結果更加可信。
通常情況下,可以設定cv引數來控制幾折,但是我們希望對其劃分等加以控制,所以出現了KFold,KFold控制劃分折,可以控制劃分折的數目,是否打亂順序等,可以賦值給cv,用來控制劃分。

 

程式碼:

from sklearn.datasets import load_iris
from sklearn.model_selection import StratifiedKFold ,cross_val_score
from sklearn.linear_model import LogisticRegression
import warnings

warnings.filterwarnings('ignore')

iris_data = load_iris()
logreg = LogisticRegression()
strKFold = StratifiedKFold(n_splits=3,shuffle=False,random_state=0)
scores = cross_val_score(logreg,iris_data.data,iris_data.target,cv=strKFold)
print("straitified cross validation scores:{}".format(scores))
print("Mean score of straitified cross validation:{:.2f}".format(scores.mean()))

  

結果:

straitified cross validation scores:[0.96078431 0.92156863 0.95833333]
Mean score of straitified cross validation:0.95

  

Leave-one-out Cross-validation 留一法

  留一法Leave-one-out Cross-validation:是一種特殊的交叉驗證方式。顧名思義,如果樣本容量為n,則k=n,進行n折交叉驗證,每次留下一個樣本進行驗證。主要針對小樣本資料。

程式碼:

from sklearn.datasets import load_iris
from sklearn.model_selection import LeaveOneOut , cross_val_score
from sklearn.linear_model import LogisticRegression
import  warnings

warnings.filterwarnings('ignore')

iris = load_iris()
logreg = LogisticRegression()
loout = LeaveOneOut()
scores = cross_val_score(logreg,iris.data,iris.target,cv=loout)
print("leave-one-out cross validation scores:{}".format(scores))
print("Mean score of leave-one-out cross validation:{:.2f}".format(scores.mean()))

  

結果:

leave-one-out cross validation scores:[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. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 0. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 0. 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. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1.]
Mean score of leave-one-out cross validation:0.95

  

Shuffle-split cross-validation

  控制更加靈活,可以控制劃分迭代次數,每次劃分測試集和訓練集的比例(也就說:可以存在機不再訓練集也不再測試集的情況)

程式碼:

from sklearn.datasets import load_iris
from sklearn.model_selection import ShuffleSplit,cross_val_score
from sklearn.linear_model import LogisticRegression
import warnings

warnings.filterwarnings('ignore')

iris = load_iris()
# 迭代八次
shufsp1 = ShuffleSplit(train_size=0.5,test_size=0.4,n_splits=8)
logreg = LogisticRegression()
scores = cross_val_score(logreg,iris.data,iris.target,cv=shufsp1)

print("shuffle split cross validation scores:\n{}".format(scores))
print("Mean score of shuffle split cross validation:{:.2f}".format(scores.mean()))

  

結果:

shuffle split cross validation scores:
[0.95       1.         0.86666667 0.95       0.88333333 0.88333333
 0.85       0.9       ]
Mean score of shuffle split cross validation:0.91

  

參考文獻:http://www.cnblogs.com/lianyingteng/p/7811126.html

https://www.cnblogs.com/magle/p/5638409.html

https://blog.csdn.net/u014248127/article/details/78885180

https://www.cnblogs.com/ysugyl/p/8707887.html

相關文章