在機(jī)器學(xué)習(xí)和數(shù)據(jù)挖掘的應(yīng)用中,scikit-learn是一個功能強(qiáng)大的python包。在數(shù)據(jù)量不是過大的情況下,可以解決大部分問題。學(xué)習(xí)使用scikit-learn的過程中,我自己也在補(bǔ)充著機(jī)器學(xué)習(xí)和數(shù)據(jù)挖掘的知識。這里根據(jù)自己學(xué)習(xí)sklearn的經(jīng)驗(yàn),我做一個總結(jié)的筆記。另外,我也想把這篇筆記一直更新下去。
1 scikit-learn基礎(chǔ)介紹
1.1 估計(jì)器(Estimator)
估計(jì)器,很多時候可以直接理解成分類器,主要包含兩個函數(shù):
- fit():訓(xùn)練算法,設(shè)置內(nèi)部參數(shù)。接收訓(xùn)練集和類別兩個參數(shù)。
- predict():預(yù)測測試集類別,參數(shù)為測試集。
大多數(shù)scikit-learn估計(jì)器接收和輸出的數(shù)據(jù)格式均為numpy數(shù)組或類似格式。
1.2 轉(zhuǎn)換器(Transformer)
轉(zhuǎn)換器用于數(shù)據(jù)預(yù)處理和數(shù)據(jù)轉(zhuǎn)換,主要是三個方法:
- fit():訓(xùn)練算法,設(shè)置內(nèi)部參數(shù)。
- transform():數(shù)據(jù)轉(zhuǎn)換。
- fit_transform():合并fit和transform兩個方法。
1.3 流水線(Pipeline)
sklearn.pipeline包
流水線的功能:
- 跟蹤記錄各步驟的操作(以方便地重現(xiàn)實(shí)驗(yàn)結(jié)果)
- 對各步驟進(jìn)行一個封裝
- 確保代碼的復(fù)雜程度不至于超出掌控范圍
基本使用方法
流水線的輸入為一連串的數(shù)據(jù)挖掘步驟,其中最后一步必須是估計(jì)器,前幾步是轉(zhuǎn)換器。輸入的數(shù)據(jù)集經(jīng)過轉(zhuǎn)換器的處理后,輸出的結(jié)果作為下一步的輸入。最后,用位于流水線最后一步的估計(jì)器對數(shù)據(jù)進(jìn)行分類。
每一步都用元組( ‘名稱’,步驟)來表示?,F(xiàn)在來創(chuàng)建流水線。
scaling_pipeline = Pipeline([
('scale', MinMaxScaler()),
('predict', KNeighborsClassifier())
])
1.4 預(yù)處理
主要在sklearn.preprcessing包下。
規(guī)范化:
- MinMaxScaler :最大最小值規(guī)范化
- Normalizer :使每條數(shù)據(jù)各特征值的和為1
- StandardScaler :為使各特征的均值為0,方差為1
編碼:
- LabelEncoder :把字符串類型的數(shù)據(jù)轉(zhuǎn)化為整型
- OneHotEncoder :特征用一個二進(jìn)制數(shù)字來表示
- Binarizer :為將數(shù)值型特征的二值化
- MultiLabelBinarizer:多標(biāo)簽二值化
1.5 特征
1.5.1 特征抽取
包:sklearn.feature_extraction
特征抽取是數(shù)據(jù)挖掘任務(wù)最為重要的一個環(huán)節(jié),一般而言,它對最終結(jié)果的影響要高過數(shù)據(jù)挖掘算法本身。只有先把現(xiàn)實(shí)用特征表示出來,才能借助數(shù)據(jù)挖掘的力量找到問題的答案。特征選擇的另一個優(yōu)點(diǎn)在于:降低真實(shí)世界的復(fù)雜度,模型比現(xiàn)實(shí)更容易操縱。
一般最常使用的特征抽取技術(shù)都是高度針對具體領(lǐng)域的,對于特定的領(lǐng)域,如圖像處理,在過去一段時間已經(jīng)開發(fā)了各種特征抽取的技術(shù),但這些技術(shù)在其他領(lǐng)域的應(yīng)用卻非常有限。
- DictVectorizer: 將dict類型的list數(shù)據(jù),轉(zhuǎn)換成numpy array
- FeatureHasher : 特征哈希,相當(dāng)于一種降維技巧
- image:圖像相關(guān)的特征抽取
- text: 文本相關(guān)的特征抽取
- text.CountVectorizer:將文本轉(zhuǎn)換為每個詞出現(xiàn)的個數(shù)的向量
- text.TfidfVectorizer:將文本轉(zhuǎn)換為tfidf值的向量
- text.HashingVectorizer:文本的特征哈希
示例

CountVectorize只數(shù)出現(xiàn)個數(shù)


TfidfVectorizer:個數(shù)+歸一化(不包括idf)

1.5.2 特征選擇
包:sklearn.feature_selection
特征選擇的原因如下:
(1)降低復(fù)雜度
(2)降低噪音
(3)增加模型可讀性
- VarianceThreshold: 刪除特征值的方差達(dá)不到最低標(biāo)準(zhǔn)的特征
- SelectKBest: 返回k個最佳特征
- SelectPercentile: 返回表現(xiàn)最佳的前r%個特征
單個特征和某一類別之間相關(guān)性的計(jì)算方法有很多。最常用的有卡方檢驗(yàn)(χ2)。其他方法還有互信息和信息熵。
- chi2: 卡方檢驗(yàn)(χ2)
1.6 降維
包:sklearn.decomposition
- 主成分分析算法(Principal Component Analysis, PCA)的目的是找到能用較少信息描述數(shù)據(jù)集的特征組合。它意在發(fā)現(xiàn)彼此之間沒有相關(guān)性、能夠描述數(shù)據(jù)集的特征,確切說這些特征的方差跟整體方差沒有多大差距,這樣的特征也被稱為主成分。這也就意味著,借助這種方法,就能通過更少的特征捕獲到數(shù)據(jù)集的大部分信息。
1.7 組合
包:**sklearn.ensemble **
組合技術(shù)即通過聚集多個分類器的預(yù)測來提高分類準(zhǔn)確率。
常用的組合分類器方法:
(1)通過處理訓(xùn)練數(shù)據(jù)集。即通過某種抽樣分布,對原始數(shù)據(jù)進(jìn)行再抽樣,得到多個訓(xùn)練集。常用的方法有裝袋(bagging)和提升(boosting)。
(2)通過處理輸入特征。即通過選擇輸入特征的子集形成每個訓(xùn)練集。適用于有大量冗余特征的數(shù)據(jù)集。隨機(jī)森林(Random forest)就是一種處理輸入特征的組合方法。
(3)通過處理類標(biāo)號。適用于多分類的情況,將類標(biāo)號隨機(jī)劃分成兩個不相交的子集,再把問題變?yōu)槎诸悊栴},重復(fù)構(gòu)建多次模型,進(jìn)行分類投票。
- BaggingClassifier: Bagging分類器組合
- BaggingRegressor: Bagging回歸器組合
- AdaBoostClassifier: AdaBoost分類器組合
- AdaBoostRegressor: AdaBoost回歸器組合
- GradientBoostingClassifier:GradientBoosting分類器組合
- GradientBoostingRegressor: GradientBoosting回歸器組合
- ExtraTreeClassifier:ExtraTree分類器組合
- ExtraTreeRegressor: ExtraTree回歸器組合
- RandomTreeClassifier:隨機(jī)森林分類器組合
- RandomTreeRegressor: 隨機(jī)森林回歸器組合
使用舉例
AdaBoostClassifier(DecisionTreeClassifier(max_depth=1),
algorithm="SAMME",
n_estimators=200)
解釋
裝袋(bagging):根據(jù)均勻概率分布從數(shù)據(jù)集中重復(fù)抽樣(有放回),每個自助樣本集和原數(shù)據(jù)集一樣大,每個自助樣本集含有原數(shù)據(jù)集大約63%的數(shù)據(jù)。訓(xùn)練k個分類器,測試樣本被指派到得票最高的類。
提升(boosting):通過給樣本設(shè)置不同的權(quán)值,每輪迭代調(diào)整權(quán)值。不同的提升算法之間的差別,一般是(1)如何更新樣本的權(quán)值,(2)如何組合每個分類器的預(yù)測。其中Adaboost中,樣本權(quán)值是增加那些被錯誤分類的樣本的權(quán)值,分類器C_i的重要性依賴于它的錯誤率。
Boosting主要關(guān)注降低偏差,因此Boosting能基于泛化性能相當(dāng)弱的學(xué)習(xí)器構(gòu)建出很強(qiáng)的集成;Bagging主要關(guān)注降低方差,因此它在不剪枝的決策樹、神經(jīng)網(wǎng)絡(luò)等學(xué)習(xí)器上效用更為明顯。偏差指的是算法的期望預(yù)測與真實(shí)預(yù)測之間的偏差程度,反應(yīng)了模型本身的擬合能力;方差度量了同等大小的訓(xùn)練集的變動導(dǎo)致學(xué)習(xí)性能的變化,刻畫了數(shù)據(jù)擾動所導(dǎo)致的影響。
1.8 模型評估(度量)
包:sklearn.metrics
sklearn.metrics包含評分方法、性能度量、成對度量和距離計(jì)算。
分類結(jié)果度量
參數(shù)大多是y_true和y_pred。
- accuracy_score:分類準(zhǔn)確度
- condusion_matrix :分類混淆矩陣
- classification_report:分類報(bào)告
- precision_recall_fscore_support:計(jì)算精確度、召回率、f、支持率
- jaccard_similarity_score:計(jì)算jcaard相似度
- hamming_loss:計(jì)算漢明損失
- zero_one_loss:0-1損失
- hinge_loss:計(jì)算hinge損失
- log_loss:計(jì)算log損失
其中,F(xiàn)1是以每個類別為基礎(chǔ)進(jìn)行定義的,包括兩個概念:準(zhǔn)確率(precision)和召回率(recall)。準(zhǔn)確率是指預(yù)測結(jié)果屬于某一類的個體,實(shí)際屬于該類的比例。召回率是被正確預(yù)測為某類的個體,與數(shù)據(jù)集中該類個體總數(shù)的比例。F1是準(zhǔn)確率和召回率的調(diào)和平均數(shù)。
回歸結(jié)果度量
- explained_varicance_score:可解釋方差的回歸評分函數(shù)
- mean_absolute_error:平均絕對誤差
- mean_squared_error:平均平方誤差
多標(biāo)簽的度量
- coverage_error:涵蓋誤差
- label_ranking_average_precision_score:計(jì)算基于排名的平均誤差Label ranking average precision (LRAP)
聚類的度量
- adjusted_mutual_info_score:調(diào)整的互信息評分
- silhouette_score:所有樣本的輪廓系數(shù)的平均值
- silhouette_sample:所有樣本的輪廓系數(shù)
1.9 交叉驗(yàn)證
包:sklearn.cross_validation
- KFold:K-Fold交叉驗(yàn)證迭代器。接收元素個數(shù)、fold數(shù)、是否清洗
- LeaveOneOut:LeaveOneOut交叉驗(yàn)證迭代器
- LeavePOut:LeavePOut交叉驗(yàn)證迭代器
- LeaveOneLableOut:LeaveOneLableOut交叉驗(yàn)證迭代器
- LeavePLabelOut:LeavePLabelOut交叉驗(yàn)證迭代器
LeaveOneOut(n) 相當(dāng)于 KFold(n, n_folds=n) 相當(dāng)于LeavePOut(n, p=1)。
LeaveP和LeaveOne差別在于leave的個數(shù),也就是測試集的尺寸。LeavePLabel和LeaveOneLabel差別在于leave的Label的種類的個數(shù)。
LeavePLabel這種設(shè)計(jì)是針對可能存在第三方的Label,比如我們的數(shù)據(jù)是一些季度的數(shù)據(jù)。那么很自然的一個想法就是把1,2,3個季度的數(shù)據(jù)當(dāng)做訓(xùn)練集,第4個季度的數(shù)據(jù)當(dāng)做測試集。這個時候只要輸入每個樣本對應(yīng)的季度Label,就可以實(shí)現(xiàn)這樣的功能。
以下是實(shí)驗(yàn)代碼,盡量自己多實(shí)驗(yàn)去理解。
#coding=utf-8
import numpy as np
import sklearnfrom sklearn
import cross_validation
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8],[9, 10]])
y = np.array([1, 2, 1, 2, 3])
def show_cross_val(method):
if method == "lolo":
labels = np.array(["summer", "winter", "summer", "winter", "spring"])
cv = cross_validation.LeaveOneLabelOut(labels)
elif method == 'lplo':
labels = np.array(["summer", "winter", "summer", "winter", "spring"])
cv = cross_validation.LeavePLabelOut(labels,p=2)
elif method == 'loo':
cv = cross_validation.LeaveOneOut(n=len(y))
elif method == 'lpo':
cv = cross_validation.LeavePOut(n=len(y),p=3)
for train_index, test_index in cv:
print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
print "X_train: ",X_train
print "y_train: ", y_train
print "X_test: ",X_test
print "y_test: ",y_test
if __name__ == '__main__':
show_cross_val("lpo")
常用方法
- train_test_split:分離訓(xùn)練集和測試集(不是K-Fold)
- cross_val_score:交叉驗(yàn)證評分,可以指認(rèn)cv為上面的類的實(shí)例
- cross_val_predict:交叉驗(yàn)證的預(yù)測。
1.10 網(wǎng)格搜索
包:sklearn.grid_search
網(wǎng)格搜索最佳參數(shù)
- GridSearchCV:搜索指定參數(shù)網(wǎng)格中的最佳參數(shù)
- ParameterGrid:參數(shù)網(wǎng)格
- ParameterSampler:用給定分布生成參數(shù)的生成器
-
RandomizedSearchCV:超參的隨機(jī)搜索
通過best_estimator_.get_params()方法,獲取最佳參數(shù)。
1.11 多分類、多標(biāo)簽分類
包:sklearn.multiclass
- OneVsRestClassifier:1-rest多分類(多標(biāo)簽)策略
- OneVsOneClassifier:1-1多分類策略
-
OutputCodeClassifier:1個類用一個二進(jìn)制碼表示
示例代碼
#coding=utf-8
from sklearn import metrics
from sklearn import cross_validation
from sklearn.svm import SVC
from sklearn.multiclass import OneVsRestClassifier
from sklearn.preprocessing import MultiLabelBinarizer
import numpy as np
from numpy import random
X=np.arange(15).reshape(5,3)
y=np.arange(5)
Y_1 = np.arange(5)
random.shuffle(Y_1)
Y_2 = np.arange(5)
random.shuffle(Y_2)
Y = np.c_[Y_1,Y_2]
def multiclassSVM():
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2,random_state=0)
model = OneVsRestClassifier(SVC())
model.fit(X_train, y_train)
predicted = model.predict(X_test)
print predicted
def multilabelSVM():
Y_enc = MultiLabelBinarizer().fit_transform(Y)
X_train, X_test, Y_train, Y_test = cross_validation.train_test_split(X, Y_enc, test_size=0.2, random_state=0)
model = OneVsRestClassifier(SVC())
model.fit(X_train, Y_train)
predicted = model.predict(X_test)
print predicted
if __name__ == '__main__':
multiclassSVM()
# multilabelSVM()
上面的代碼測試了svm在OneVsRestClassifier的包裝下,分別處理多分類和多標(biāo)簽的情況。特別注意,在多標(biāo)簽的情況下,輸入必須是二值化的。所以需要MultiLabelBinarizer()先處理。
2 具體模型
2.1 樸素貝葉斯(Naive Bayes)
包:sklearn.cross_validation

樸素貝葉斯的特點(diǎn)是分類速度快,分類效果不一定是最好的。
- GasussianNB:高斯分布的樸素貝葉斯
- MultinomialNB:多項(xiàng)式分布的樸素貝葉斯
- BernoulliNB:伯努利分布的樸素貝葉斯
所謂使用什么分布的樸素貝葉斯,就是假設(shè)P(x_i|y)是符合哪一種分布,比如可以假設(shè)其服從高斯分布,然后用最大似然法估計(jì)高斯分布的參數(shù)。



3 scikit-learn擴(kuò)展
3.0 概覽
具體的擴(kuò)展,通常要繼承sklearn.base包下的類。
- BaseEstimator: 估計(jì)器的基類
- ClassifierMixin :分類器的混合類
- ClusterMixin:聚類器的混合類
- RegressorMixin :回歸器的混合類
- TransformerMixin :轉(zhuǎn)換器的混合類
關(guān)于什么是Mixin(混合類),具體可以看這個知乎鏈接。簡單地理解,就是帶有實(shí)現(xiàn)方法的接口,可以將其看做是組合模式的一種實(shí)現(xiàn)。舉個例子,比如說常用的TfidfTransformer,繼承了BaseEstimator, TransformerMixin,因此它的基本功能就是單一職責(zé)的估計(jì)器和轉(zhuǎn)換器的組合。
3.1 創(chuàng)建自己的轉(zhuǎn)換器
在特征抽取的時候,經(jīng)常會發(fā)現(xiàn)自己的一些數(shù)據(jù)預(yù)處理的方法,sklearn里可能沒有實(shí)現(xiàn),但若直接在數(shù)據(jù)上改,又容易將代碼弄得混亂,難以重現(xiàn)實(shí)驗(yàn)。這個時候最好自己創(chuàng)建一個轉(zhuǎn)換器,在后面將這個轉(zhuǎn)換器放到pipeline里,統(tǒng)一管理。
例如《Python數(shù)據(jù)挖掘入門與實(shí)戰(zhàn)》書中的例子,我們想接收一個numpy數(shù)組,根據(jù)其均值將其離散化,任何高于均值的特征值替換為1,小于或等于均值的替換為0。
代碼實(shí)現(xiàn):
from sklearn.base import TransformerMixin
from sklearn.utils import as_float_array
class MeanDiscrete(TransformerMixin):
#計(jì)算出數(shù)據(jù)集的均值,用內(nèi)部變量保存該值。
def fit(self, X, y=None):
X = as_float_array(X)
self.mean = np.mean(X, axis=0)
#返回self,確保在轉(zhuǎn)換器中能夠進(jìn)行鏈?zhǔn)秸{(diào)用(例如調(diào)用transformer.fit(X).transform(X))
return self
def transform(self, X):
X = as_float_array(X)
assert X.shape[1] == self.mean.shape[0]
return X > self.mean