借著別人的文章(王圣元 [王的機(jī)器] ),復(fù)盤一下python的基礎(chǔ)知識(shí)點(diǎn)。感謝原作者的分享!
Sklearn (全稱 Scikit-Learn) 是基于 Python 語言的機(jī)器學(xué)習(xí)工具。它建立在 NumPy, SciPy, Pandas 和 Matplotlib 之上,里面的 API 的設(shè)計(jì)非常好,所有對象的接口簡單,很適合新手上路。
在 Sklearn 里面有六大任務(wù)模塊:分別是分類、回歸、聚類、降維、模型選擇和預(yù)處理,如下圖從其官網(wǎng)的截屏。

要使用上述六大模塊的方法,可以用以下的偽代碼,注意 import 后面我用的都是一些通用名稱,如 SomeClassifier, SomeRegressor, SomeModel,具體化的名稱由具體問題而定,比如
- SomeClassifier = RandomForestClassifier
- SomeRegressor = LinearRegression
- SomeModel = KMeans, PCA
- SomeModel = GridSearchCV, OneHotEncoder
# 分類 (Classification)
from sklearn import SomeClassifier
from sklearn.linear_model import SomeClassifier
from sklearn.ensemble import SomeClassifier
# 回歸 (Regression)
from sklearn import SomeRegressor
from sklearn.linear_model import SomeRegressor
from sklearn.ensemble import SomeRegressor
# 聚類 (Clustering)
from sklearn.cluster import SomeModel
# 降維 (Dimensionality Reduction)
from sklearn.decomposition import SomeModel
# 模型選擇 (Model Selection)
from sklearn.model_selection import SomeModel
# 預(yù)處理 (Preprocessing)
from sklearn.preprocessing import SomeModel
SomeClassifier, SomeRegressor, SomeModel 其實(shí)都叫做估計(jì)器 (estimator),就像 Python 里「萬物皆對象」那樣,Sklearn 里「萬物皆估計(jì)器」。
此外,Sklearn 里面還有很多自帶數(shù)據(jù)集供,引入它們的偽代碼如下。
數(shù)據(jù)集 (Dataset)
from sklearn.datasets import SomeData
本文我們用以下思路來講解:
第一章介紹機(jī)器學(xué)習(xí),從定義出發(fā)引出機(jī)器學(xué)習(xí)四要素:數(shù)據(jù)、任務(wù)、性能度量和模型。加這一章的原因是不把機(jī)器學(xué)習(xí)相關(guān)概念弄清楚之后很難完全弄明白 Sklearn。
第二章介紹 Sklearn,從其 API 設(shè)計(jì)原理出發(fā)分析其五大特點(diǎn):一致性、可檢驗(yàn)、標(biāo)準(zhǔn)類、可組合和默認(rèn)值。最后再分析 Sklearn 里面自帶數(shù)據(jù)以及儲(chǔ)存格式。
第三章介紹 Sklearn 里面的三大核心 API,包括估計(jì)器、預(yù)測器和轉(zhuǎn)換器。這一章的內(nèi)容最重要,幾乎所有模型都會(huì)用到這三大 API。
第四章介紹 Sklearn 里面的高級(jí) API,即元估計(jì)器,有可以大大簡化代碼量的流水線 (Pipeline 估計(jì)器),有集成模型 (Ensemble 估計(jì)器)、有多類別-多標(biāo)簽-多輸出分類模型 (Multiclass 和 Multioutput 估計(jì)器) 和模型選擇工具 (Model Selection 估計(jì)器)。
1 機(jī)器學(xué)習(xí)簡介
1.1 定義和組成元素
什么是機(jī)器學(xué)習(xí)?字面上來講就是 (人用) 計(jì)算機(jī)來學(xué)習(xí)。談起機(jī)器學(xué)習(xí)就一定要提起湯姆米切爾 (Tom M.Mitchell),就像談起音樂就會(huì)提起貝多芬,談起籃球就會(huì)提起邁克爾喬丹,談起電影就會(huì)提起萊昂納多迪卡普里奧。米切爾對機(jī)器學(xué)習(xí)定義的原話是:
A computer program is said to learn from experience E with respect to some class of tasks T and performance measure P if its performance at tasks in T, as measured by P, improves with experience E.
假設(shè)用性能度量 P 來評(píng)估機(jī)器在某類任務(wù) T 的性能,若該機(jī)器通利用經(jīng)驗(yàn) E 在任務(wù) T 中改善其性能 P,那么可以說機(jī)器對經(jīng)驗(yàn) E 進(jìn)行了學(xué)習(xí)。
在該定義中,除了核心詞機(jī)器和學(xué)習(xí),還有關(guān)鍵詞經(jīng)驗(yàn) E,性能度量 P 和任務(wù) T。在計(jì)算機(jī)系統(tǒng)中,通常經(jīng)驗(yàn) E 是以數(shù)據(jù) D 的形式存在,而機(jī)器學(xué)習(xí)就是給定不同的任務(wù) T 從數(shù)據(jù)中產(chǎn)生模型 M,模型 M 的好壞就用性能度量 P 來評(píng)估。
由上述機(jī)器學(xué)習(xí)的定義可知機(jī)器學(xué)習(xí)包含四個(gè)元素:
數(shù)據(jù) (Data),任務(wù) (Task),性能度量 (Quality Metric) 和 模型 (Model)

1.2 數(shù)據(jù)
數(shù)據(jù) (data) 是經(jīng)驗(yàn)的另一種說法,也是信息的載體。數(shù)據(jù)可分為
- 結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù) (按數(shù)據(jù)具體類型劃分)
- 原始數(shù)據(jù)和加工數(shù)據(jù) (按數(shù)據(jù)表達(dá)形式劃分)
- 樣本內(nèi)數(shù)據(jù)和樣本外數(shù)據(jù) (按數(shù)據(jù)統(tǒng)計(jì)性質(zhì)劃分)
在統(tǒng)計(jì)中,把研究對象的全體稱為總體 (population),而把組成總體的各個(gè)元素稱為個(gè)體,把從總體中抽取的若干個(gè)體稱為樣本 (sample)。舉個(gè)調(diào)查中國男性平均身高的例子:普查所有男性金錢花費(fèi)和時(shí)間成本太高,通常會(huì)抽取若干男性作為樣本,計(jì)算樣本里的男性平均身高作為總體里的所有男性平均身高的推理 (inference)。
統(tǒng)計(jì)學(xué)中做的事情就是用樣本數(shù)據(jù)的統(tǒng)計(jì) (statistics) 來推出總體數(shù)據(jù)的參數(shù) (parameter)。樣本數(shù)據(jù)也叫做樣本內(nèi)數(shù)據(jù),除樣本內(nèi)數(shù)據(jù)之外的總體數(shù)據(jù)叫做樣本外數(shù)據(jù)。
在機(jī)器學(xué)習(xí)中,樣本內(nèi)和樣本外數(shù)據(jù)的定義稍微有些不同
樣本內(nèi)數(shù)據(jù)是用來訓(xùn)練模型的數(shù)據(jù),也叫訓(xùn)練數(shù)據(jù)。它們是已知的,可計(jì)算統(tǒng)計(jì)的。樣本外數(shù)據(jù)是未來的沒見過的新數(shù)據(jù)。它們是未知的,不可計(jì)算統(tǒng)計(jì)的。
1.3 任務(wù)
根據(jù)學(xué)習(xí)的任務(wù)模式 (訓(xùn)練數(shù)據(jù)是否有標(biāo)簽),機(jī)器學(xué)習(xí)可分為四大類:
- 有監(jiān)督學(xué)習(xí) (有標(biāo)簽)
- 無監(jiān)督學(xué)習(xí) (無標(biāo)簽)
- 半監(jiān)督學(xué)習(xí) (有部分標(biāo)簽)
- 增強(qiáng)學(xué)習(xí) (有評(píng)級(jí)標(biāo)簽)
深度學(xué)習(xí)只是一種方法,而不是任務(wù)模式,因此與上面四類不屬于同一個(gè)維度,但是深度學(xué)習(xí)與它們可以疊加成:深度有監(jiān)督學(xué)習(xí)、深度非監(jiān)督學(xué)習(xí)、深度半監(jiān)督學(xué)習(xí)和深度增強(qiáng)學(xué)習(xí)。遷移學(xué)習(xí)也是一種方法,也可以分類為有監(jiān)督遷移學(xué)習(xí)、非監(jiān)督遷移學(xué)習(xí)、半監(jiān)督遷移學(xué)習(xí)和增強(qiáng)遷移學(xué)習(xí)。
1.4 性能度量
回歸和分類任務(wù)中最常見的誤差函數(shù)以及一些有用的性能度量如下。

除上述損失函數(shù)之外,分類任務(wù)還有很多其他有用的性能度量。
錯(cuò)誤率:分類錯(cuò)誤的樣本數(shù)占樣本總數(shù)的比例稱為錯(cuò)誤率 (error rate),相應(yīng)的分類正確的樣本數(shù)占樣本總數(shù)的比例稱為精度 (accuracy)。在 10 個(gè)樣本中有 2 個(gè)樣本分類錯(cuò)誤,則錯(cuò)誤率為 20%,而精度為 80%。
查準(zhǔn)率和查全率:錯(cuò)誤率和精度雖然常用,但是不能滿足所有任務(wù)需求。假定用訓(xùn)練好的模型預(yù)測騎士贏球,顯然,錯(cuò)誤率衡量了多少比賽實(shí)際是贏球但預(yù)測成輸球。但是若我們關(guān)心的是“預(yù)測出的比賽中有多少是贏球”,或“贏球的比賽中有多少被預(yù)測出了”,那么錯(cuò)誤率這個(gè)單一指標(biāo)顯然就不夠用了,這時(shí)需要引進(jìn)更為細(xì)分的性能度量,即查準(zhǔn)率 (precision) 和查全率 (recall)。
其他概念比如混淆矩陣、ROC、AUC 我們再下帖的實(shí)例用到時(shí)再細(xì)講。
1.5 模型
有監(jiān)督模型如下圖所示:

無監(jiān)督模型包括各種聚類分析 (KMeans, DBSCAN)、主成分分析 (PCA)、獨(dú)立成分分析 (ICA)、隱含狄利克雷分配 (LDA) 等等。
2 Sklearn 數(shù)據(jù)
Sklearn 和之前討論的 NumPy, SciPy, Pandas, Matplotlib 相似,就是一個(gè)處理特殊任務(wù)的包,Sklearn 就是處理機(jī)器學(xué)習(xí) (有監(jiān)督學(xué)習(xí)和無監(jiān)督學(xué)習(xí)) 的包,更精確的說,它里面有六個(gè)任務(wù)模塊和一個(gè)數(shù)據(jù)引入模塊:
有監(jiān)督學(xué)習(xí)的分類任務(wù)
有監(jiān)督學(xué)習(xí)的回歸任務(wù)
無監(jiān)督學(xué)習(xí)的聚類任務(wù)
無監(jiān)督學(xué)習(xí)的降維任務(wù)
數(shù)據(jù)預(yù)處理任務(wù)
模型選擇任務(wù)
數(shù)據(jù)引入
2.1 數(shù)據(jù)格式
在 Sklean 里,模型能即用的數(shù)據(jù)有兩種形式:
- Numpy 二維數(shù)組 (ndarray) 的稠密數(shù)據(jù) (dense data),通常都是這種格式。
- SciPy 矩陣 (scipy.sparse.matrix) 的稀疏數(shù)據(jù) (sparse data),比如文本分析每個(gè)單詞 (字典有 100000 個(gè)詞) 做獨(dú)熱編碼得到矩陣有很多 0,這時(shí)用 ndarray 就不合適了,太耗內(nèi)存。
上述數(shù)據(jù)在機(jī)器學(xué)習(xí)中通常用符號(hào) X 表示,是模型自變量。它的大小 = [樣本數(shù), 特征數(shù)]。有監(jiān)督學(xué)習(xí)除了需要特征 X 還需要標(biāo)簽 y,而 y 通常就是 Numpy 一維數(shù)組,無監(jiān)督學(xué)習(xí)沒有 y。
2.2 自帶數(shù)據(jù)集
Sklearn 里面有很多自帶數(shù)據(jù)集供用戶使用。來看看 Sklearn 三種引入數(shù)據(jù)形式。
打包好的數(shù)據(jù):對于小數(shù)據(jù)集,用 sklearn.datasets.load_*
分流下載數(shù)據(jù):對于大數(shù)據(jù)集,用 sklearn.datasets.fetch_*
隨機(jī)創(chuàng)建數(shù)據(jù):為了快速展示,用 sklearn.datasets.make_*
3 核心 API
Sklearn 里萬物皆估計(jì)器。估計(jì)器是個(gè)非常抽象的叫法,可把它不嚴(yán)謹(jǐn)?shù)漠?dāng)成一個(gè)模型 (用來回歸、分類、聚類、降維),或當(dāng)成一套流程 (預(yù)處理、網(wǎng)格最終)。
本節(jié)三大 API 其實(shí)都是估計(jì)器:
- 估計(jì)器 (estimator) 當(dāng)然是估計(jì)器
- 預(yù)測器 (predictor) 是具有預(yù)測功能的估計(jì)器
- 轉(zhuǎn)換器 (transformer) 是具有轉(zhuǎn)換功能的估計(jì)器
這三句看似廢話,其實(shí)蘊(yùn)藏了很多內(nèi)容。其實(shí)我對第 1 點(diǎn)這個(gè)估計(jì)器的起名不太滿意,我覺得應(yīng)該叫擬合器 (fitter) - 具有擬合功能的估計(jì)器??赐赀@一節(jié)你就會(huì)明白「擬合器」這種叫法更合理。
3.1 估計(jì)器
定義:任何可以基于數(shù)據(jù)集對一些參數(shù)進(jìn)行估計(jì)的對象都被稱為估計(jì)器。
兩個(gè)核心點(diǎn):1. 需要輸入數(shù)據(jù),2. 可以估計(jì)參數(shù)。估計(jì)器首先被創(chuàng)建,然后被擬合。
創(chuàng)建估計(jì)器:需要設(shè)置一組超參數(shù),比如
- 線性回歸里超參數(shù) normalize=True
- K 均值里超參數(shù) n_clusters=3
在創(chuàng)建好的估計(jì)器 model 可以直接訪問這些超參數(shù),用 . 符號(hào)。
- model.normalize
- model.n_clusters
但 model 中有很多超參數(shù),你不可能一開始都知道要設(shè)置什么值,沒設(shè)置的用 Sklearn 會(huì)給個(gè)合理的默認(rèn)值,因此新手不用擔(dān)心。
擬合估計(jì)器:需要訓(xùn)練集。
在有監(jiān)督學(xué)習(xí)中的代碼范式為:model.fit( X_train, y_train )
在無監(jiān)督學(xué)習(xí)中的代碼范式為:model.fit( X_train )
擬合之后可以訪問 model 里學(xué)到的參數(shù),比如線性回歸里的特征前的系數(shù) coef_,或 K 均值里聚類標(biāo)簽 labels_。
- model.coef_
- model.labels_
說了這么多抽象的東西,現(xiàn)在展示有監(jiān)督學(xué)習(xí)的「線性回歸」的具體例子。
線性回歸
# 首先從 sklearn 下的 linear_model 中引入 LinearRegression,再創(chuàng)建估計(jì)器起名 model,設(shè)置超參數(shù) normalize 為 **True**,指的在每個(gè)特征值上做標(biāo)準(zhǔn)化,這樣會(huì)加速數(shù)值運(yùn)算。
from sklearn.linear_model import LinearRegression
model = LinearRegression(normalize=True)
# 自己創(chuàng)建一個(gè)簡單數(shù)據(jù)集 (沒有噪聲完全線性) 只為了講解估計(jì)器里面的特征。
x = np.arange(10)
y = 2 * x + 1
plt.plot( x, y, 'o' )
# Sklearn 里模型要求特征 X 是個(gè)兩維變量么 (樣本數(shù)×特征數(shù))?但在本例中 X 是一維,因?yàn)槲覀冇?np.newaxis 加一個(gè)維度,它做的事情就是把 [1, 2, 3] 轉(zhuǎn)成 [[1],[2],[3]]。再把 X 和 y 丟進(jìn) fit() 函數(shù)來擬合線性模型的參數(shù)。
X = x[:, np.newaxis]
model.fit( X, y )
#擬合完后的估計(jì)器和創(chuàng)建完的樣子看起來一樣,但是已經(jīng)用「model.param_」可以訪問到學(xué)好的參數(shù)了,展示如下。
print( model.coef_ )
print( model.intercept_ )
3.2 預(yù)測器
定義:預(yù)測器在估計(jì)器上做了一個(gè)延展,延展出預(yù)測的功能。
兩個(gè)核心點(diǎn):1. 基于學(xué)到的參數(shù)預(yù)測,2. 預(yù)測有很多指標(biāo)。最常見的就是 predict() 函數(shù):
model.predict(X_test):評(píng)估模型在新數(shù)據(jù)上的表現(xiàn)
model.predict(X_train):確認(rèn)模型在老數(shù)據(jù)上的表現(xiàn)
舉個(gè)例子:
# 加載數(shù)據(jù)集
from sklearn.datasets import load_iris
iris = load_iris()
# 切分?jǐn)?shù)據(jù)集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split( iris['data'], iris['target'], test_size=0.2 )
# 創(chuàng)建估計(jì)器
from sklearn.linear_model import LinearRegression
model = LinearRegression(solver = 'lbfgs')
# 擬合估計(jì)器
model.fit(X_train, y_train)
# 預(yù)測器
y_pred = model.predict( X_test ) #預(yù)測的類別
p_pred = model.predict_proba( X_test ) # 預(yù)測該類別的信心
預(yù)測器里還有額外的兩個(gè)函數(shù)可以使用。在分類問題中
score() 返回的是分類準(zhǔn)確率
decision_function() 返回的是每個(gè)樣例在每個(gè)類下的分?jǐn)?shù)值
print( model.score( X_test, y_test ) )
decision_score = model.decision_function( X_test )
print( decision_score )
小節(jié): 估計(jì)器都有 fit() 方法,預(yù)測器都有 predict() 和 score() 方法,言外之意不是每個(gè)預(yù)測器都有 predict_proba() 和 decision_function() 方法
3.3 轉(zhuǎn)換器
定義:轉(zhuǎn)換器也是一種估計(jì)器,兩者都帶擬合功能,但估計(jì)器做完擬合來預(yù)測,而轉(zhuǎn)換器做完擬合來轉(zhuǎn)換。
核心點(diǎn):估計(jì)器里 fit + predict,轉(zhuǎn)換器里 fit + transform。
本節(jié)介紹兩大類轉(zhuǎn)換器
- 將分類型變量 (categorical) 編碼成數(shù)值型變量 (numerical)
- 規(guī)范化 (normalize) 或標(biāo)準(zhǔn)化 (standardize) 數(shù)值型變量
3.3.1分類型變量編碼
LabelEncoder & OrdinalEncoder
LabelEncoder和 OrdinalEncoder 都可以將字符轉(zhuǎn)成數(shù)字,但是
LabelEncoder的輸入是一維,比如 1d ndarray
OrdinalEncoder 的輸入是二維,比如 DataFrame
# 首先給出要編碼的列表 enc 和要解碼的列表 dec。
enc = ['win','draw','lose','win']
dec = ['draw','draw','win']
# LabelEncoder編碼
# 從 sklearn 下的 preprocessing 中引入 LabelEncoder,再創(chuàng)建轉(zhuǎn)換器起名 LE。
from sklearn.preprocessing import LabelEncoder
LE = LabelEncoder()
print( LE.fit(enc) ) --LabelEncoder()
print( LE.classes_ ) --['draw' 'lose' 'win']
print( LE.transform(dec) ) --[0 0 2]
# OrdinalEncoder編碼
# 從 sklearn 下的 preprocessing 中引入 OrdinalEncoder,再創(chuàng)建轉(zhuǎn)換器起名 OE
from sklearn.preprocessing import OrdinalEncoder
OE = OrdinalEncoder()
enc_DF = pd.DataFrame(enc)
dec_DF = pd.DataFrame(dec)
print( OE.fit(enc_DF) ) --OrdinalEncoder(categories='auto', dtype=<class 'numpy.float64'>)
print( OE.categories_ ) --[array(['draw', 'lose', 'win'], dtype=object)]
print( OE.transform(dec_DF) ) --[[0.] [0.] [2.]]
OneHotEncoder
轉(zhuǎn)換器 OneHotEncoder 可以接受兩種類型的輸入:
- 用 LabelEncoder 編碼好的一維數(shù)組
- DataFrame
from sklearn.preprocessing import OneHotEncoder
# 1. 用 LabelEncoder 編碼好的一維數(shù)組 (元素為整數(shù)),重塑 成二維數(shù)組作為 OneHotEncoder 輸入。
OHE = OneHotEncoder()
num = LE.fit_transform( enc )
print( num ) --[2 0 1 2]
OHE_y = OHE.fit_transform( num.reshape(-1,1) )
OHE_y.toarray() # 想看該矩陣?yán)锞唧w內(nèi)容,用 toarray() 函數(shù)。
--array([[0., 0., 1.],
[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
# 2. 用 DataFrame作為 OneHotEncoder 輸入
OHE = OneHotEncoder()
OHE.fit_transform( enc_DF ).toarray()
3.3.2特征縮放
數(shù)據(jù)要做的最重要的轉(zhuǎn)換之一是特征縮放 (feature scaling)。當(dāng)輸入的數(shù)值的量剛不同時(shí),機(jī)器學(xué)習(xí)算法的性能都不會(huì)好。具體來說,對于某個(gè)特征,我們有兩種方法:
- 標(biāo)準(zhǔn)化 (standardization):每個(gè)維度的特征減去該特征均值,除以該維度的標(biāo)準(zhǔn)差。
- 規(guī)范化 (normalization):每個(gè)維度的特征減去該特征最小值,除以該特征的最大值與最小值之差。
MinMaxScaler 與 StandardScaler
整套轉(zhuǎn)換器「先創(chuàng)建再 fit 在 transform」的流程應(yīng)該很清楚了。自己讀下面代碼看看是不是秒懂。唯一需要注意的就是輸入 X 要求是兩維。
# MinMaxScaler
from sklearn.preprocessing import MinMaxScaler
X = np.array( [0, 0.5, 1, 1.5, 2, 100] )
X_scale = MinMaxScaler().fit_transform( X.reshape(-1,1) )
# StandardScaler
from sklearn.preprocessing import StandardScaler
X_scale = StandardScaler().fit_transform( X.reshape(-1,1) )
警示: fit() 函數(shù)只能作用在訓(xùn)練集上,千萬不要作用在測試集上,要不然你就犯了數(shù)據(jù)窺探的錯(cuò)誤了!拿標(biāo)準(zhǔn)化舉例,用訓(xùn)練集 fit 出來的均值和標(biāo)準(zhǔn)差參數(shù),來對測試集做標(biāo)準(zhǔn)化。
4 高級(jí) API
Sklearn 里核心 API 接口是估計(jì)器,那高級(jí) API 接口就是元估計(jì)器 (meta-estimator),即由很多基估計(jì)器 (base estimator) 組合成的估計(jì)器。元估計(jì)器把估計(jì)器當(dāng)成參數(shù)。代碼范式大概如下:
meta_model( base_model )
本節(jié)討論五大元估計(jì)器,分別帶集成功能的 ensemble,多分類和多標(biāo)簽的 multiclass,多輸出的 multioutput,選擇模型的 model_selection,和流水線的 pipeline。
1 ensemble.BaggingClassifier
2 ensemble.VotingClassifier
3 multiclass.OneVsOneClassifier
4 multiclass.OneVsRestClassifier
5 multioutput.MultiOutputClassifier
6 model_selection.GridSearchCV
7 model_selection.RandomizedSearchCV
8 pipeline.Pipeline
在下面五節(jié),我們會(huì)用的鳶尾花數(shù)據(jù) iris 和數(shù)字?jǐn)?shù)據(jù) digits,還有一些自己創(chuàng)建的數(shù)據(jù)。
4.1 Ensemble 估計(jì)器
Ensemble 估計(jì)器是用來做集成學(xué)習(xí),該估計(jì)器里面有若干個(gè)分類器 (classifier) 或回歸器 (regressor)。
最常用的 Ensemble 估計(jì)器排列如下:
-
AdaBoostClassifier: 逐步提升分類器 -
AdaBoostRegressor: 逐步提升回歸器 -
BaggingClassifier: 裝袋分類器 -
BaggingRegressor: 裝袋回歸器 -
GradientBoostingClassifier: 梯度提升分類器 -
GradientBoostingRegressor: 梯度提升回歸器 -
RandomForestClassifier: 隨機(jī)森林分類器 -
RandomForestRegressor: 隨機(jī)森林回歸器 -
VotingClassifier: 投票分類器 -
VotingRegressor: 投票回歸器
我們用鳶尾花數(shù)據(jù) iris,拿
含同質(zhì)估計(jì)器 RandomForestClassifier
含異質(zhì)估計(jì)器 VotingClassifier
來舉例。首先將數(shù)據(jù)分成 80:20 的訓(xùn)練集和測試集,并引入 metrics 來計(jì)算各種性能指標(biāo)。
from sklearn.datasets import load_iris
iris = load_iris()
from sklearn.model_selection import train_test_split
from sklearn import metrics
X_train, X_test, y_train, y_test = train_test_split( iris['data'], iris['target'], test_size=0.2 )```
RandomForestClassifier
隨機(jī)森林 (random forest) 是決策樹 (decision tree) 的一種集成模型,每棵決策樹處理的數(shù)據(jù)用裝袋法 (bagging) 生成。隨機(jī)森林可以減小預(yù)測的方差,并且可以評(píng)估特征重要性。
from sklearn.ensemble import RandomForestClassifier
# 4 棵決策樹 (森林由樹組成);此外每棵樹的最大樹深為 5
RF = RandomForestClassifier( n_estimators=4, max_depth=5 )
RF.fit( X_train, y_train )
# 擬合 RF 完再做預(yù)測
print ( "RF - Accuracy (Train): %.4g" % metrics.accuracy_score(y_train, RF.predict(X_train)) )
--RF - Accuracy (Train): 0.9833
print ( "RF - Accuracy (Test): %.4g" % metrics.accuracy_score(y_test, RF.predict(X_test)) )
--RF - Accuracy (Test): 1
print( RF.n_estimators ) --4
RF.estimators_

VotingClassifier
和隨機(jī)森林由同質(zhì)分類器「決策樹」不同,投票分類器由若干個(gè)異質(zhì)分類器組成。下例用 VotingClassifier 建立個(gè)含有對率回歸 (LR)、隨機(jī)森林 (RF) 和高斯樸素貝葉斯 (GNB) 三個(gè)分類器的集成模型。
RandomForestClassifier 的基分類器只能是決策樹,因此只用通過控制 n_estimators 超參數(shù)來決定樹的個(gè)數(shù),而 VotingClassifier 的基分類器要實(shí)實(shí)在在的輸入其本身
from sklearn.linear_model import LinearRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
LR = LinearRegression(solver= 'lbfgs', multi_class='multinomial')
RF = RandomForestClassifier( n_estimators=5)
GNB = GaussianNB()
Ensemble = VotingClassifier(estimators = [('lr', LR), ('rf', RF),
('gnb', GNB)], voting='hard' )
Ensemble.fit( X_train, y_train )
print( len(Ensemble.estimators_) )
Ensemble.estimators_

比較元估計(jì)器和它三個(gè)組成元素的表現(xiàn)。還是集成后的 Ensemble 表現(xiàn)最好。
LR.fit( X_train, y_train )
RF.fit( X_train, y_train )
GNB.fit( X_train, y_train )

LR - Accuracy (Train): 0.975
RF - Accuracy (Train): 0.9833
GNB - Accuracy (Train): 0.95
Ensemble - Accuracy (Train): 0.9833
LR - Accuracy (Test): 1
RF - Accuracy (Test): 1
GNB - Accuracy (Test): 1
Ensemble - Accuracy (Test): 1
4.2 Multiclass 估計(jì)器
sklearn.multiclass 可以處理多類別 (multi-class) 的多標(biāo)簽 (multi-label) 的分類問題。
從小節(jié) 4.2 到 4.4,我們都會(huì)使用數(shù)字?jǐn)?shù)據(jù)集 digits。首先將數(shù)據(jù)分成 80:20 的訓(xùn)練集和測試集。
from sklearn.datasets import load_digits
digits = load_digits()
digits.keys()
X_train, X_test, y_train, y_test
= train_test_split( digits['data'],
digits['target'],
test_size=0.2 )
4.2.1 多類別分類
手寫數(shù)字有 0-9 十類,但手頭上只有兩分類估計(jì)器 (比如像支撐向量機(jī)) 怎么用呢?我們可以采取下面三種常見策略:
一對一 (One vs One, OvO):一個(gè)分類器用來處理數(shù)字 0 和數(shù)字 1,一個(gè)用來處理數(shù)字 0 和數(shù)字 2,一個(gè)用來處理數(shù)字 1 和 2,以此類推。N 個(gè)類需要 N(N-1)/2 個(gè)分類器。
一對其他 (One vs All, OvA):訓(xùn)練 10 個(gè)二分類器,每一個(gè)對應(yīng)一個(gè)數(shù)字,第一個(gè)分類 1 和「非1」,第二個(gè)分類 2 和「非2」,以此類推。N 個(gè)類需要 N 個(gè)分類器。
OneVsOneClassifier

print( len(ovo_lr.estimators_) )
ovo_lr.estimators

OneVsRestClassifier

print( len(ova_lr.estimators_) )
ova_lr.estimators_

4.2.2 多標(biāo)簽分類
為了闡明「多標(biāo)簽分類」的原理。在手寫數(shù)字的例子上,我們特意為每個(gè)數(shù)字設(shè)計(jì)了多標(biāo)簽:
標(biāo)簽 1 - 奇數(shù)、偶數(shù)
標(biāo)簽 2 - 小于等于 4,大于 4
再建立多標(biāo)簽 y_train_multilabel,代碼如下 (OneVsRestClassifier 也可以用來做多標(biāo)簽分類):
from sklearn.multiclass import OneVsRestClassifier
y_train_multilabel = np.c_[ y_train%2==0, y_train<=4 ]
print(y_train_multilabel) --[[ True True] [False False] [False False] ... [False False] [False False] [False False]]
訓(xùn)練模型,只不過這時(shí)用的是 y_train_multilabel。

print( len(ova_ml.estimators_) )
ova_ml.estimators_

4.3 Multioutput 估計(jì)器*
sklearn.multioutput 可以處理多輸出 (multi-output) 的分類問題。
Multioutput 估計(jì)器有兩個(gè):
MultiOutputRegressor: 多輸出回歸MultiOutputClassifier: 多輸出分類
本節(jié)只關(guān)注多輸出分類。
MultiOutputClassifier
首先引入 MultiOutputClassifier 和 RandomForestClassifier。你看,這兩個(gè)都是元估計(jì)器,因此在 Sklearn 里面估計(jì)器可以隨意組合。
from sklearn.multioutput import MultiOutputClassifier
from sklearn.ensemble import RandomForestClassifier
在手寫數(shù)字的例子上,我們也為特意每個(gè)數(shù)字設(shè)計(jì)了多標(biāo)簽而且每個(gè)標(biāo)簽的類別都大于二。
- 標(biāo)簽 1 - 小于等于 4,4 和 7 之間,大于等于 7 (三類)
- 標(biāo)簽 2 - 數(shù)字本身 (十類)
代碼如下:
from sklearn.multioutput import MultiOutputClassifier
from sklearn.ensemble import RandomForestClassifier
用含有 100 棵決策樹的隨機(jī)森林來解決這個(gè)多輸入分類問題。

# 這個(gè)模型在測試集前五張照片上的預(yù)測。
MO.predict( X_test[:5,:] )
--array([[0, 2],
[0, 2],
[0, 0],
[2, 9],
[1, 5]])
# 真實(shí)標(biāo)簽
y_test_1st = y_test.copy()
y_test_1st[ y_test<=4 ] = 0
y_test_1st[ np.logical_and(y_test>4, y_test<7) ] = 1
y_test_1st[ y_test>=7 ] = 2
y_test_multioutput
= np.c_[ y_test_1st, y_test ]
y_test_multioutput[:5]
--array([[0, 2],
[0, 2],
[0, 0],
[2, 9],
[1, 5]]
4.4 Model Selection 估計(jì)器
模型選擇 (Model Selction) 在機(jī)器學(xué)習(xí)非常重要,它主要用于評(píng)估模型表現(xiàn),常見的 Model Selection 估計(jì)器有以下幾個(gè):
cross_validate: 評(píng)估交叉驗(yàn)證的表現(xiàn)。learning_curve: 建立學(xué)習(xí)曲線。GridSearchCV: 用交叉驗(yàn)證從網(wǎng)格中一組超參數(shù)搜索出最佳超參數(shù)。RandomizedSearchCV: 用交叉驗(yàn)證從一組隨機(jī)超參數(shù)搜索出最佳超參數(shù)。
本小節(jié)關(guān)注調(diào)節(jié)超參數(shù)的兩個(gè)估計(jì)器,即上面列出的最后兩個(gè)。它們都要用到交叉驗(yàn)證,我們來看這兩個(gè)調(diào)參的估計(jì)器,網(wǎng)格追蹤和隨機(jī)追蹤。
網(wǎng)格追蹤:參數(shù) 1 在 [1, 10, 100, 1000] 中取值,**參數(shù) 2 **在 [0.01, 0.1, 1 10] 中取值,注意并不是等間距取值。模型在所有 16 個(gè)組合跑,選取一對對應(yīng)最小交叉驗(yàn)證誤差的參數(shù)。
隨機(jī)追蹤:根據(jù)指定分布隨機(jī)搜索,可以選擇獨(dú)立于參數(shù)個(gè)數(shù),比如 log(參數(shù) 1) 服從 0 到 3 的均勻分布, log(參數(shù) 2) 服從 -2 到 1 的均勻分布。此外,會(huì)設(shè)定一個(gè)預(yù)算參數(shù)。
原理講清楚了,看代碼吧。

4.5 Pipeline 估計(jì)器
Pipeline 估計(jì)器又叫流水線,把各種估計(jì)器串聯(lián) (Pipeline) 或并聯(lián) (FeatureUnion) 的方式組成一條龍服務(wù)。用好了它真的能大大提高效率。
4.5.1 Pipeline
Pipeline 將若干個(gè)估計(jì)器按順序連在一起,比如
特征提取 -> 降維 -> 擬合 -> 預(yù)測
在整個(gè) Pipeline 中,它的屬性永遠(yuǎn)和最后一個(gè)估計(jì)器屬性一樣
如果最后一個(gè)估計(jì)器是預(yù)測器,那么 Pipeline 是預(yù)測器
如果最后一個(gè)估計(jì)器是轉(zhuǎn)換器,那么 Pipeline 是轉(zhuǎn)換器
下面用一個(gè)簡單例子來說明如果用 Pipeline 來做「先填補(bǔ)缺失值-再標(biāo)準(zhǔn)化」這兩步的。先生成含缺失值 NaN 的數(shù)據(jù) X。

首先引入 Pipeline,再引入
處理缺失值的轉(zhuǎn)換器 SimpleImputer
做規(guī)劃化的轉(zhuǎn)換器 MinMaxScaler

由于最后一個(gè)估計(jì)器是轉(zhuǎn)換器,因此 pipe 也是個(gè)轉(zhuǎn)換器。寫好了就可以那它來做「先填補(bǔ)缺失值-再標(biāo)準(zhǔn)化」的重復(fù)工作了。
看看運(yùn)行結(jié)果,值都被填滿了,而且兩列也被標(biāo)準(zhǔn)化了。

4.5.2 FeatureUnion
如果我們想在一個(gè)節(jié)點(diǎn)同時(shí)運(yùn)行幾個(gè)估計(jì)器,我們可用 FeatureUnion。下例首先建立一個(gè) DataFrame,
前兩列智力 IQ 和脾氣 temper 都是分類型變量
后兩列收入 income 和身高 height 都是數(shù)值型變量
每列中都有缺失值



我們現(xiàn)在按下列步驟來清洗數(shù)據(jù)。
對分類型變量:獲取 -> 中位數(shù)填充 -> 獨(dú)熱編碼
對數(shù)值型變量:獲取 -> 均值填充 -> 標(biāo)準(zhǔn)化
上面兩步是平行進(jìn)行的。
首先我們自己定義一個(gè)從 DataFrame 里面獲取每列的類,起名叫 DataFrameSelector。

接下來建立一個(gè)流水線 full_pipe,它并聯(lián)著兩個(gè)流水線
- categorical_pipe 處理分類型變量
DataFrameSelector 用來獲取
SimpleImputer 用出現(xiàn)最多的值來填充 None
OneHotEncoder 來編碼返回非稀疏矩陣 - numeric_pipe 處理數(shù)值型變量
DataFrameSelector 用來獲取
SimpleImputer 用均值來填充 NaN
normalize 來規(guī)范化數(shù)值
下面代碼非常漂亮。

將結(jié)果打印出來,齊活!
X_proc = full_pipe.fit_transform( X )
print( X_proc )
5 總結(jié)
結(jié)合本帖講的總結(jié)一套機(jī)器學(xué)習(xí)的初級(jí)框架:
確定任務(wù):是「有監(jiān)督」的分類或回歸?還是「無監(jiān)督」的聚類或降維?確定好后基本就能知道用 Sklearn 里哪些模型了。
數(shù)據(jù)預(yù)處理:這步最繁瑣,要處理缺失值、異常值;要編碼分類型變量;要正規(guī)化或標(biāo)準(zhǔn)化數(shù)值型變量,等等。但是有了 Pipeline 神器一切變得簡單高效。
訓(xùn)練和評(píng)估:這步最簡單,訓(xùn)練用估計(jì)器 fit() 先擬合,評(píng)估用預(yù)測器 predict() 來評(píng)估。
選擇模型:啟動(dòng) Model Selection 估計(jì)器里的 GridSearchCV 和 RandomizedSearchCV,選擇得分最高的那組超參數(shù) (即模型)。