Scikit-learn 秘籍 第四章 使用 scikit-learn 對(duì)數(shù)據(jù)分類

第四章 使用 scikit-learn 對(duì)數(shù)據(jù)分類

作者:Trent Hauck

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

分類在大量語境下都非常重要。例如挚赊,如果我們打算自動(dòng)化一些決策過程遂跟,我們可以利用分類。在我們需要研究詐騙的情況下郑原,有大量的事務(wù)砸喻,人去檢查它們是不實(shí)際的陶珠。所以挟裂,我們可以使用分類都自動(dòng)化這種決策。

4.1 使用決策樹實(shí)現(xiàn)基本的分類

這個(gè)秘籍中揍诽,我們使用決策樹執(zhí)行基本的分類诀蓉。它們是非常不錯(cuò)的模型,因?yàn)樗鼈兒芤子诶斫馐畲啵⑶乙坏┯?xùn)練完成渠啤,評(píng)估就很容易。通程砺穑可以使用 SQL 語句沥曹,這意味著結(jié)果可以由許多人使用。

準(zhǔn)備

這個(gè)秘籍中碟联,我們會(huì)看一看決策樹妓美。我喜歡將決策樹看做基類,大量的模型從中派生鲤孵。它是個(gè)非常簡(jiǎn)單的想法壶栋,但是適用于大量的情況。

首先普监,讓我們獲取一些分類數(shù)據(jù)贵试,我們可以使用它來練習(xí):

>>> from sklearn import datasets 
>>> X, y = datasets.make_classification(n_samples=1000, n_features=3,
                                        n_redundant=0)

操作步驟

處理決策樹非常簡(jiǎn)單。我們首先需要導(dǎo)入對(duì)象凯正,之后訓(xùn)練模型:


>>> from sklearn.tree import DecisionTreeClassifier 
>>> dt = DecisionTreeClassifier() 
>>> dt.fit(X, y) DecisionTreeClassifier(compute_importances=None, criterion='gini',
                        max_depth=None, max_features=None,
                        max_leaf_nodes=None, min_density=None,
                        min_samples_leaf=1, min_samples_split=2,
                        random_state=None, splitter='best')
>>> preds = dt.predict(X) 
>>> (y == preds).mean() 
1.0

你可以看到毙玻,我們猜測(cè)它是正確的。顯然廊散,這只是湊合著運(yùn)行∠海現(xiàn)在我們研究一些選項(xiàng)。

首先奸汇,如果你觀察dt對(duì)象施符,它擁有多種關(guān)鍵字參數(shù)往声,決定了對(duì)象的行為。我們?nèi)绾芜x擇對(duì)象十分重要戳吝,所以我們要詳細(xì)觀察對(duì)象的效果浩销。

我們要觀察的第一個(gè)細(xì)節(jié)是max_depth。這是個(gè)重要的參數(shù)听哭,決定了允許多少分支慢洋。這非常重要,因?yàn)闆Q策樹需要很長時(shí)間來生成樣本外的數(shù)據(jù)陆盘,它們帶有一些類型的正則化普筹。之后,我們會(huì)看到隘马,我們?nèi)绾问褂枚喾N淺層決策樹太防,來生成更好的模型。讓我們創(chuàng)建更復(fù)雜的數(shù)據(jù)集并觀察當(dāng)我們?cè)试S不同max_depth時(shí)會(huì)發(fā)生什么酸员。我們會(huì)將這個(gè)數(shù)據(jù)及用于剩下的秘籍蜒车。


>>> n_features=200 
>>> X, y = datasets.make_classification(750, n_features,
                                        n_informative=5) 
>>> import numpy as np 
>>> training = np.random.choice([True, False], p=[.75, .25],
                                size=len(y))

>>> accuracies = []

>>> for x in np.arange(1, n_features+1): 
>>> dt = DecisionTreeClassifier(max_depth=x)    
>>> dt.fit(X[training], y[training])    
>>> preds = dt.predict(X[~training])    
>>> accuracies.append((preds == y[~training]).mean())

>>> import matplotlib.pyplot as plt

>>> f, ax = plt.subplots(figsize=(7, 5))

>>> ax.plot(range(1, n_features+1), accuracies, color='k')

>>> ax.set_title("Decision Tree Accuracy") 
>>> ax.set_ylabel("% Correct") 
>>> ax.set_xlabel("Max Depth")

輸出如下:

我們可以看到,我們實(shí)際上在較低最大深度處得到了漂亮的準(zhǔn)確率幔嗦。讓我們進(jìn)一步看看低級(jí)別的準(zhǔn)確率酿愧,首先是 15:

>>> N = 15 
>>> import matplotlib.pyplot as plt 
>>> f, ax = plt.subplots(figsize=(7, 5))
>>> ax.plot(range(1, n_features+1)[:N], accuracies[:N], color='k')
>>> ax.set_title("Decision Tree Accuracy") 
>>> ax.set_ylabel("% Correct") 
>>> ax.set_xlabel("Max Depth")

輸出如下:

這個(gè)就是我們之前看到的峰值。比較令人驚訝的是它很快就下降了邀泉。最大深度 1 到 3 可能幾乎是相等的嬉挡。決策樹很擅長分離規(guī)則,但是需要控制汇恤。

我們觀察compute_importances參數(shù)棘伴。對(duì)于隨機(jī)森林來說,它實(shí)際上擁有更廣泛的含義屁置。但是我們要更好地了解它焊夸。同樣值得注意的是,如果你使用了 0.16 或之前的版本蓝角,你可以盡管這樣做:


>>> dt_ci = DecisionTreeClassifier(compute_importances=True) 
>>> dt.fit(X, y)
#plot the importances 
>>> ne0 = dt.feature_importances_ != 0

>>> y_comp = dt.feature_importances_[ne0] 
>>> x_comp = np.arange(len(dt.feature_importances_))[ne0]

>>> import matplotlib.pyplot as plt

>>> f, ax = plt.subplots(figsize=(7, 5)) 
>>> ax.bar(x_comp, y_comp)

輸出如下:

要注意阱穗,你可能會(huì)得到一個(gè)錯(cuò)誤,讓你知道你不再需要顯式設(shè)置compute_importances使鹅。

我們看到揪阶,這些特征之一非常重要,后面跟著幾個(gè)其它特征患朱。

工作原理

簡(jiǎn)單來說鲁僚,我們所有時(shí)間都在構(gòu)造決策樹。當(dāng)思考場(chǎng)景以及將概率分配給結(jié)果時(shí),我們構(gòu)造了決策樹冰沙。我們的規(guī)則更加復(fù)雜侨艾,并涉及很多上下文,但是使用決策樹拓挥,我們關(guān)心的所有東西都是結(jié)果之間的差異唠梨,假設(shè)特征的一些信息都是已知的。

現(xiàn)在侥啤,讓我們討論熵和基尼系數(shù)之間的差異当叭。

熵不僅僅是給定變量的熵值,如果我們知道元素的值盖灸,它表示了熵中的變化蚁鳖。這叫做信息增益(IG),數(shù)學(xué)上是這樣:

IG(Data,KnownFeatures) = H(Data) - H(Data|KnownFeatures)

對(duì)于基尼系數(shù)赁炎,我們關(guān)心的是醉箕,提供新的信息,一個(gè)數(shù)據(jù)點(diǎn)有多可能被錯(cuò)誤標(biāo)記甘邀。

熵和基尼系數(shù)都有優(yōu)缺點(diǎn)琅攘。也就是說垮庐,如果你觀察它們工作方式的主要差異松邪,這可能是個(gè)重新驗(yàn)證你的假設(shè)的好方式。

4.2 調(diào)整決策樹模型

如果我們僅僅使用基本的決策樹實(shí)現(xiàn)哨查,可能擬合得不是很好逗抑。所以我們需要調(diào)參,以便獲得更好的擬合寒亥。這非常簡(jiǎn)單邮府,并且不用花費(fèi)什么精力。

準(zhǔn)備

這個(gè)秘籍中溉奕,我們深入了解如何調(diào)整決策樹分類器褂傀。有幾個(gè)渲染,并且在上一個(gè)秘籍中加勤,我們僅僅查看了它們之一仙辟。

我們會(huì)訓(xùn)練一個(gè)基本的模型,并實(shí)際觀察決策樹是什么樣子鳄梅。之后叠国,我們會(huì)重新檢測(cè)每個(gè)決策,并且指出不同的修改如何影響結(jié)構(gòu)戴尸。

如果你打算遵循這個(gè)秘籍粟焊,需要安裝pydot

操作步驟

比起其它算法,決策樹有許多“把手”项棠,因?yàn)槲覀冃D(zhuǎn)把手時(shí)悲雳,易于發(fā)現(xiàn)發(fā)生了什么。

>>> from sklearn import datasets 
>>> X, y = datasets.make_classification(1000, 20, n_informative=3)
>>> from sklearn.tree import DecisionTreeClassifier 
>>> dt = DecisionTreeClassifier() 
>>> dt.fit(X, y) 

好的沾乘,所以既然我們訓(xùn)練了基本的分類器怜奖,我們可以快速地查看它:

>>> from StringIO import StringIO
>>> from sklearn import tree 
>>> import pydot
>>> str_buffer = StringIO() 
>>> tree.export_graphviz(dt, out_file=str_buffer) 
>>> graph = pydot.graph_from_dot_data(str_buffer.getvalue()) 
>>> graph.write("myfile.jpg")

這張圖幾乎難以辨認(rèn),但是這展示了一顆復(fù)雜的樹翅阵,它可以使用非最優(yōu)的決策樹歪玲,作為結(jié)果生成。

哇哦掷匠!這是個(gè)非常復(fù)雜的樹滥崩,看上去對(duì)數(shù)據(jù)過擬合了。首先讹语,讓我們降低最大深度值:

>>> dt = DecisionTreeClassifier(max_depth=5) 
>>> dt.fit(X, y); 

順帶一說钙皮,如果你想知道為什么能看到分號(hào),通常是repr顽决,它實(shí)際上是決策樹的模型短条。例如fit函數(shù)實(shí)際上返回決策樹對(duì)象,它允許鏈?zhǔn)秸{(diào)用:

>>> dt = DecisionTreeClassifier(max_depth=5).fit(X, y) 

現(xiàn)在才菠,讓我們返回正常的程序茸时。

由于我們會(huì)多次繪制它,我們創(chuàng)建一個(gè)函數(shù)赋访。

>>> def plot_dt(model, filename):
       str_buffer = StringIO() 
>>> tree.export_graphviz(model, out_file=str_buffer)    
>>> graph = pydot.graph_from_dot_data(str_buffer.getvalue()) 
>>> graph.write_jpg(filename)
>>> plot_dt(dt, "myfile.png")

會(huì)生成下面的圖:

這棵樹稍微簡(jiǎn)單了一些可都。讓我們看看,如果我們將熵用作分割標(biāo)準(zhǔn)蚓耽,會(huì)發(fā)生什么:

>>> dt = DecisionTreeClassifier(criterion='entropy',
                                 max_depth=5).fit(X, y) 
>>> plot(dt, "entropy.png") 

會(huì)生成下面的圖:

很容易看到渠牲,前兩個(gè)分割是相同特征,之后的分割以相似總數(shù)分布步悠。這是個(gè)良好的合理的檢查签杈。

同樣,注意第一個(gè)分割的熵是 0.999鼎兽,但是使用基尼系數(shù)的時(shí)候是 0.5答姥。我們需要弄清楚,決策樹的分割的兩種度量有什么不同接奈。更多信息請(qǐng)見下面的工作原理一節(jié)踢涌。但是,如果我們想要使用熵穿件決策樹序宦,我們必須使用下列命令:

>>> dt = DecisionTreeClassifier(min_samples_leaf=10,
                                criterion='entropy',
                                max_depth=5).fit(X, y)

工作原理

決策樹睁壁,通常容易出現(xiàn)過擬合。由于它的自身特性,決策樹經(jīng)常會(huì)過擬合潘明,所以行剂,我們需要思考,如何避免過擬合钳降,這是為了避免復(fù)雜性厚宰。實(shí)戰(zhàn)中,簡(jiǎn)單的模型通常會(huì)執(zhí)行得更好遂填。

我們即將在實(shí)戰(zhàn)中看到這個(gè)理念铲觉。隨機(jī)森林會(huì)在簡(jiǎn)單模型的理念上構(gòu)建。

4.3 使用許多決策樹 -- 隨機(jī)森林

這個(gè)秘籍中吓坚,我們會(huì)將隨機(jī)森林用于分類任務(wù)撵幽。由于隨機(jī)森林對(duì)于過擬合非常健壯,并且在大量場(chǎng)景中表現(xiàn)良好礁击,所以使用它盐杂。

準(zhǔn)備

我們會(huì)在工作原理一節(jié)中深入探索,但是隨即森林通過構(gòu)造大量淺層樹哆窿,之后讓每顆樹為分類投票链烈,再選取投票結(jié)果。這個(gè)想法在機(jī)器學(xué)習(xí)中十分有效挚躯。如果我們發(fā)現(xiàn)簡(jiǎn)單訓(xùn)練的分類器只有 60% 的準(zhǔn)確率强衡,我們可以訓(xùn)練大量分類器,它們通常是正確的秧均,并且隨后一起使用它們食侮。

操作步驟

訓(xùn)練隨機(jī)森林分類器的機(jī)制在 Scikit 中十分容易号涯。這一節(jié)中目胡,我們執(zhí)行以下步驟:

  1. 創(chuàng)建用于練習(xí)的樣例數(shù)據(jù)集

  2. 訓(xùn)練基本的隨機(jī)森林對(duì)象

  3. 看一看訓(xùn)練對(duì)象的一些屬性

下一個(gè)秘籍中,我們會(huì)觀察如何調(diào)整隨機(jī)森林分類器链快,讓我們以導(dǎo)入數(shù)據(jù)集來開始:

>>> from sklearn import datasets 

之后誉己,使用 1000 個(gè)樣例創(chuàng)建數(shù)據(jù)集:

>>> X, y = datasets.make_classification(1000) 

既然我們擁有了數(shù)據(jù),我們可以創(chuàng)建分類器對(duì)象并訓(xùn)練它:

>>> from sklearn.ensemble import RandomForestClassifier
>>> rf = RandomForestClassifier()
>>> rf.fit(X, y) 

我們想做的第一件事域蜗,就是看看如何擬合訓(xùn)練數(shù)據(jù)巨双。我們可以將predict方法用于這些東西:

>>> print "Accuracy:\t", (y == rf.predict(X)).mean() 
Accuracy:   0.993
>>> print "Total Correct:\t", (y == rf.predict(X)).sum() Total 
Correct:   993 

現(xiàn)在,讓我們查看一些屬性和犯法霉祸。

首先筑累,我們查看一些實(shí)用屬性。這里丝蹭,由于我們保留默認(rèn)值慢宗,它們是對(duì)象的默認(rèn)值:

  • rf.criterion:這是決定分割的標(biāo)準(zhǔn)。默認(rèn)是gini

  • rf.bootstrap:布爾值镜沽,表示在訓(xùn)練隨機(jī)森林時(shí)是否使用啟動(dòng)樣例

  • rf.n_jobs:訓(xùn)練和預(yù)測(cè)的任務(wù)數(shù)量敏晤。如果你打算使用所有處理器,將其設(shè)置為-1缅茉。要記住嘴脾,如果你的數(shù)據(jù)集不是非常大,使用過多任務(wù)通常會(huì)導(dǎo)致浪費(fèi)蔬墩,因?yàn)樘幚砥髦g需要序列化和移動(dòng)译打。

  • rf.max_features:這表示執(zhí)行最優(yōu)分割時(shí),考慮的特征數(shù)量拇颅。在調(diào)參過程中這會(huì)非常方便扶平。

  • rf.conpute_importtances:這有助于我們決定,是否計(jì)算特征的重要性蔬蕊。如何使用它的信息结澄,請(qǐng)見更多一節(jié)。

  • rf.max_depth:這表示樹的深度岸夯。

有許多屬性需要注意麻献,更多信息請(qǐng)查看官方文檔。

不僅僅是predect方法很實(shí)用猜扮,我們也可以從獨(dú)立的樣子獲取概率勉吻。這是個(gè)非常實(shí)用的特性,用于理解每個(gè)預(yù)測(cè)的不確定性旅赢。例如齿桃,我們可以預(yù)測(cè)每個(gè)樣例對(duì)于不同類的概率。

>>> probs = rf.predict_proba(X)
>>> import pandas as pd
>>> probs_df = pd.DataFrame(probs, columns=['0', '1']) >>> probs_df['was_correct'] = rf.predict(X) == y
>>> import matplotlib.pyplot as plt
>>> f, ax = plt.subplots(figsize=(7, 5))
>>> probs_df.groupby('0').was_correct.mean().plot(kind='bar', ax=ax) 
>>> ax.set_title("Accuracy at 0 class probability")
>>> ax.set_ylabel("% Correct") 
>>> ax.set_xlabel("% trees for 0") 

工作原理

隨機(jī)森輪實(shí)用預(yù)定義數(shù)量的弱決策樹煮盼,并且使用數(shù)據(jù)的自己訓(xùn)練每一顆樹短纵。這對(duì)于避免過擬合至關(guān)重要。這也是bootstrap參數(shù)的原因僵控。我們的每個(gè)樹擁有下列東西:

  • 票數(shù)最多的類

  • 輸出香到,如果我們使用回歸樹

當(dāng)然,它們是表現(xiàn)上的考量报破,這會(huì)在下一個(gè)秘籍中設(shè)計(jì)悠就。但是出于禮節(jié)隨機(jī)森林如何工作的目的,我們訓(xùn)練一些平均數(shù)充易,作為結(jié)果梗脾,獲得了非常好的分類器。

更多

特征重要性是隨機(jī)森林的不錯(cuò)的副產(chǎn)品盹靴。這通常有助于回答一個(gè)問題:如果我們擁有 10 個(gè)特征炸茧,對(duì)于判斷數(shù)據(jù)點(diǎn)的真實(shí)類別帆疟,哪個(gè)特征是最重要的?真實(shí)世界中的應(yīng)用都易于觀察宇立。例如踪宠,如果一個(gè)事務(wù)是不真實(shí)的,我們可能想要了解妈嘹,是否有特定的信號(hào)柳琢,可以用于更快弄清楚事務(wù)的類別。

如果我們打算極端特征重要性润脸,我們需要在我們創(chuàng)建對(duì)象時(shí)說明柬脸。如果你使用 scikit-learn 0.15,你可能會(huì)得到一個(gè)警告毙驯,說這不是必需的倒堕。在 0.16 中,警告會(huì)被移除爆价。

>>> rf = RandomForestClassifier(compute_importances=True) 
>>> rf.fit(X, y) 
>>> f, ax = plt.subplots(figsize=(7, 5)) 
>>> ax.bar(range(len(rf.feature_importances_)),            rf.feature_importances_) 
>>> ax.set_title("Feature Importances")

下面就是輸出:

我們可以看到垦巴,在判斷結(jié)果是類 0 或者 1 時(shí),特定的特征比其它特征重要铭段。

4.4 調(diào)整隨機(jī)森林模型

在上一個(gè)秘籍中骤宣,我們學(xué)習(xí)了如何使用隨機(jī)森林分類器。在這個(gè)秘籍中序愚,我們會(huì)瀏覽如何通過調(diào)整參數(shù)來調(diào)整它的表現(xiàn)憔披。

準(zhǔn)備

為了調(diào)整隨機(jī)森林模型,我們首先需要?jiǎng)?chuàng)建數(shù)據(jù)集爸吮,它有一些難以預(yù)測(cè)筛欢。之后憔杨,我們修改參數(shù)并且做一些預(yù)處理來更好地?cái)M合數(shù)據(jù)集魁巩。

所以诫尽,讓我們首先創(chuàng)建數(shù)據(jù)集:

>>> from sklearn import datasets 
>>> X, y = datasets.make_classification(n_samples=10000,
                                        n_features=20,
                                        n_informative=15,
                                        flip_y=.5, weights=[.2, .8])

操作步驟

這個(gè)秘籍中健爬,我們執(zhí)行下列操作:

  1. 創(chuàng)建訓(xùn)練和測(cè)試集谋旦。和上個(gè)秘籍不同件炉,如果不與訓(xùn)練集比較峻凫,調(diào)整模型就毫無用途纫事。

  2. 訓(xùn)練基本的隨機(jī)森林勘畔,來評(píng)估原始算法有多好。

  3. 用系統(tǒng)化的方式修改一些參數(shù)丽惶,之后觀察擬合會(huì)發(fā)生什么變化炫七。

好了,啟動(dòng)解釋器并導(dǎo)入 NumPy:

>>> import numpy as np 
>>> training = np.random.choice([True, False], p=[.8, .2],
                                size=y.shape)
>>> from sklearn.ensemble import RandomForestClassifier
>>> rf = RandomForestClassifier() 
>>> rf.fit(X[training], y[training])
>>> preds = rf.predict(X[~training])
>>> print "Accuracy:\t", (preds == y[~training]).mean() 
Accuracy: 0.652239557121 

我打算用一些花招钾唬,引入模型評(píng)估度量之一万哪,我們會(huì)在這本書后面討論它侠驯。準(zhǔn)確率是第一個(gè)不錯(cuò)的度量,但是使用混淆矩陣會(huì)幫助我們理解發(fā)生了什么奕巍。

讓我們迭代max_features的推薦選項(xiàng)吟策,并觀察對(duì)擬合有什么影響。我們同事迭代一些浮點(diǎn)值的止,它們是所使用的特征的分?jǐn)?shù)檩坚。使用下列命令:

>>> from sklearn.metrics import confusion_matrix
>>> max_feature_params = ['auto', 'sqrt', 'log2', .01, .5, .99]
>>> confusion_matrixes = {}
>>> for max_feature in max_feature_params:
        rf = RandomForestClassifier(max_features=max_feature)
        rf.fit(X[training], y[training])    
>>> confusion_matrixes[max_feature] = confusion_matrix(y[~training])
>>> rf.predict(X[~training])).ravel() 

由于我使用了ravel方法,我們的二維數(shù)組現(xiàn)在變成了一維诅福。

現(xiàn)在匾委,導(dǎo)入 Pandas 并查看剛剛創(chuàng)建的混淆矩陣:

>>> import pandas as pd

>>> confusion_df = pd.DataFrame(confusion_matrixes)

>>> import itertools 
>>> from matplotlib import pyplot as plt 
>>> f, ax = plt.subplots(figsize=(7, 5))

>>> confusion_df.plot(kind='bar', ax=ax)

>>> ax.legend(loc='best')

>>> ax.set_title("Guessed vs Correct (i, j) where i is the guess and j is the actual.")

>>> ax.grid()

>>> ax.set_xticklabels([str((i, j)) for i, j list(itertools.product(range(2), range(2)))]); 
>>> ax.set_xlabel("Guessed vs Correct") 
>>> ax.set_ylabel("Correct")

雖然我們看不到表現(xiàn)中的任何真正的差異,對(duì)于你自己的項(xiàng)目來說氓润,這是個(gè)非常簡(jiǎn)單的過程赂乐。讓我們?cè)囈辉?code>n_estimator選項(xiàng),但是使用原始的精確度咖气。使用一些更多的選項(xiàng)挨措,我們的圖表就會(huì)變得很密集,難以使用崩溪。

由于我們正在使用混淆矩陣运嗜,我們可以從混淆矩陣的跡除以總和來計(jì)算準(zhǔn)確度。

>>> n_estimator_params = range(1, 20)
>>> confusion_matrixes = {}
>>> for n_estimator in n_estimator_params:
        rf = RandomForestClassifier(n_estimators=n_estimator)
        rf.fit(X[training], y[training])
        confusion_matrixes[n_estimator] = confusion_matrix(y[~training],
                                          rf.predict(X[~training]))
        # here's where we'll update the confusion matrix with the operation we talked about   
>>> accuracy = lambda x: np.trace(x) / np.sum(x, dtype=float) 
>>> confusion_matrixes[n_estimator] = accuracy(confusion_matrixes[n_estimator])
>>> accuracy_series = pd.Series(confusion_matrixes) 
>>> import itertools 
>>> from matplotlib import pyplot as plt
>>> f, ax = plt.subplots(figsize=(7, 5))
>>> accuracy_series.plot(kind='bar', ax=ax, color='k', alpha=.75) 
>>> ax.grid()
>>> ax.set_title("Accuracy by Number of Estimators") 
>>> ax.set_ylim(0, 1) # we want the full scope 
>>> ax.set_ylabel("Accuracy") 
>>> ax.set_xlabel("Number of Estimators")

輸出如下:

現(xiàn)在對(duì)于大多數(shù)部分悯舟,準(zhǔn)確度是如何上升的呢担租?確實(shí)有一些隨機(jī)性和準(zhǔn)確度相關(guān),但是圖像從左到右是上升的抵怎。在下面的工作原理一節(jié)奋救,我們會(huì)討論隨機(jī)森林和 bootstrap 之間的關(guān)系,以及哪個(gè)通常更好反惕。

工作原理

bootstarp 是個(gè)不錯(cuò)的技巧尝艘,用于擴(kuò)展模型的其它部分。通常用于介紹 bootstarp 的案例是將標(biāo)準(zhǔn)誤差與中位數(shù)相加姿染。這里背亥,我們估算了結(jié)果,并將估算聚集為概率悬赏。

所以狡汉,通過簡(jiǎn)單增加估算器的數(shù)量,我們?cè)黾恿俗訕颖久銎模a(chǎn)生了整體上更快的收斂盾戴。

更多

我們可能打算加快訓(xùn)練過程。我之前提到了這個(gè)過程兵多,但是同時(shí)尖啡,我們可以將n_jobs設(shè)為我們想要訓(xùn)練的樹的數(shù)量橄仆。這應(yīng)該大致等于機(jī)器的核數(shù)。

>>> rf = RandomForestClassifier(n_jobs=4, verbose=True) 
>>> rf.fit(X, y) 
[Parallel(n_jobs=4)]: Done  1 out of  4 | elapsed:  0.3s remaining: 0.9s 
[Parallel(n_jobs=4)]: Done  4 out of  4 | elapsed:  0.3s finished 

這也可以并行預(yù)測(cè):

>>> rf.predict(X) 
[Parallel(n_jobs=4)]: Done  1 out of  4 | elapsed:  0.0s remaining:    0.0s 
[Parallel(n_jobs=4)]: Done  4 out of  4 | elapsed:  0.0s finished 

array([1, 1, 0, ..., 1, 1, 1])

4.5 使用支持向量機(jī)對(duì)數(shù)據(jù)分類

支持向量機(jī)(SVM)是我們使用的技巧之一衅斩,它不能輕易用概率解釋盆顾。SVM 背后的原理是,我們尋找一個(gè)平面畏梆,椎扬,它將數(shù)據(jù)集分割為組,并且是最優(yōu)的具温。這里蚕涤,分割的意思是,平面的選擇使平面上最接近的點(diǎn)之間的間距最大铣猩。這些點(diǎn)叫做支持向量揖铜。

準(zhǔn)備

SVM 是我最喜歡的機(jī)器學(xué)習(xí)算法之一,它是我在學(xué)校中學(xué)習(xí)的第一批機(jī)器學(xué)習(xí)伏安法之一达皿。所以天吓,讓我們獲得一些數(shù)據(jù)并開始吧。

>>> from sklearn import datasets 
>>> X, y = datasets.make_classification()

操作步驟

創(chuàng)建支持向量機(jī)分類器的機(jī)制非常簡(jiǎn)單峦椰。有許多可用的選項(xiàng)龄寞。所以,我們執(zhí)行下列操作:

  1. 創(chuàng)建 SVC 對(duì)象汤功,并訓(xùn)練一些偽造數(shù)據(jù)物邑。

  2. 使用 SVC 對(duì)象訓(xùn)練一些示例數(shù)據(jù)。

  3. 稍微討論一些 SVC 選項(xiàng)滔金。

從支持向量機(jī)模塊導(dǎo)入支持向量分類器(SVC):

>>> from sklearn.svm import SVC
>>> base_svm = SVC()
>>> base_svm.fit(X, y) 

讓我們看一些屬性:

  • C:以防我們的數(shù)據(jù)集不是分離好的色解,C會(huì)在間距上放大誤差。隨著C變大餐茵,誤差的懲罰也會(huì)變大科阎,SVM 會(huì)嘗試尋找一個(gè)更窄的間隔,即使它錯(cuò)誤分類了更多數(shù)據(jù)點(diǎn)忿族。

  • class_weight:這個(gè)表示問題中的每個(gè)類應(yīng)該給予多少權(quán)重锣笨。這個(gè)選項(xiàng)以字典提供,其中類是鍵道批,值是與這些類關(guān)聯(lián)的權(quán)重错英。

  • gamma:這是用于核的 Gamma 參數(shù),并且由rgb, sigmoidploy支持屹徘。

  • kernel:這是所用的核走趋,我們?cè)谙旅媸褂?code>linear核,但是rgb更流行噪伊,并且是默認(rèn)選項(xiàng)簿煌。

工作原理

我們?cè)跍?zhǔn)備一節(jié)中說過,SVM 會(huì)嘗試尋找一個(gè)屏幕鉴吹,它使兩個(gè)類別最優(yōu)分割姨伟。讓我們查看帶有兩個(gè)特征的最簡(jiǎn)單示例,以及一個(gè)良好分割的結(jié)果豆励。

首先夺荒,讓我們訓(xùn)練數(shù)據(jù)集,之后我們將其繪制出來良蒸。

>>> X, y = datasets.make_blobs(n_features=2, centers=2) 
>>> from sklearn.svm import LinearSVC 
>>> svm = LinearSVC() 
>>> svm.fit(X, y) 

既然我們訓(xùn)練了支持向量機(jī)技扼,我們將圖中每個(gè)點(diǎn)結(jié)果繪制出來。這會(huì)向我們展示近似的決策邊界嫩痰。

>>> from itertools import product 
>>> from collections import namedtuple

>>> Point = namedtuple('Point', ['x', 'y', 'outcome']) 
>>> decision_boundary = [] 
>>> xmin, xmax = np.percentile(X[:, 0], [0, 100]) 
>>> ymin, ymax = np.percentile(X[:, 1], [0, 100])

>>> for xpt, ypt in product(np.linspace(xmin-2.5, xmax+2.5, 20),
    np.linspace(ymin-2.5, ymax+2.5, 20)):
        p = Point(xpt, ypt, svm.predict([xpt, ypt]))
            decision_boundary.append(p)

>>> import matplotlib.pyplot as plt 
>>> f, ax = plt.subplots(figsize=(7, 5)) 
>>> import numpy as np 
>>> colors = np.array(['r', 'b']) 
>>> for xpt, ypt, pt in decision_boundary:
        ax.scatter(xpt, ypt, color=colors[pt[0]], alpha=.15)
        ax.scatter(X[:, 0], X[:, 1], color=colors[y], s=30)
        ax.set_ylim(ymin, ymax)
        ax.set_xlim(xmin, xmax)
        ax.set_title("A well separated dataset")

輸出如下:

讓我們看看其他例子剿吻,但是這一次決策邊界不是那么清晰:

>>> X, y = datasets.make_classification(n_features=2,
                                        n_classes=2,            
                                        n_informative=2,        
                                        n_redundant=0)

我們已經(jīng)看到,這并不是用線性分類易于解決的問題串纺。

雖然我們不會(huì)將其用于實(shí)戰(zhàn)丽旅,讓我們看一看決策邊界。首先纺棺,讓我們使用新的數(shù)據(jù)點(diǎn)重新訓(xùn)練分類器榄笙。


>>> svm.fit(X, y) 
>>> xmin, xmax = np.percentile(X[:, 0], [0, 100]) 
>>> ymin, ymax = np.percentile(X[:, 1], [0, 100]) 
>>> test_points = np.array([[xx, yy] for xx, yy in
                           product(np.linspace(xmin, xmax),
                           np.linspace(ymin, ymax))]) 
>>> test_preds = svm.predict(test_points)
>>> import matplotlib.pyplot as plt 
>>> f, ax = plt.subplots(figsize=(7, 5)) 
>>> import numpy as np 
>>> colors = np.array(['r', 'b']) 
>>> ax.scatter(test_points[:, 0], test_points[:, 1],
               color=colors[test_preds], alpha=.25) 
>>> ax.scatter(X[:, 0], X[:, 1], color=colors[y]) 
>>> ax.set_title("A well separated dataset") 

輸出如下:

我們可以看到,決策邊界并不完美祷蝌,但是最后茅撞,這是我們獲得的最好的線性 SVM。

更多

隨讓我們可能不能獲得更好的線性 SVM巨朦,Scikit 中的 SVC 分類器會(huì)使用徑向基函數(shù)乡翅。我們之前看過這個(gè)函數(shù),但是讓我們觀察它如何計(jì)算我們剛剛擬合的數(shù)據(jù)集的決策邊界罪郊。


>>> radial_svm = SVC(kernel='rbf') 
>>> radial_svm.fit(X, y) 
>>> xmin, xmax = np.percentile(X[:, 0], [0, 100]) 
>>> ymin, ymax = np.percentile(X[:, 1], [0, 100])
>>> test_points = np.array([[xx, yy] for xx, yy in
                           product(np.linspace(xmin, xmax),
                           np.linspace(ymin, ymax))]) 
>>> test_preds = radial_svm.predict(test_points)
>>> import matplotlib.pyplot as plt 
>>> f, ax = plt.subplots(figsize=(7, 5)) 
>>> import numpy as np 
>>> colors = np.array(['r', 'b']) 
>>> ax.scatter(test_points[:, 0], test_points[:, 1],
               color=colors[test_preds], alpha=.25) 
>>> ax.scatter(X[:, 0], X[:, 1], color=colors[y]) 
>>> ax.set_title("SVM with a radial basis function") 

輸出如下:

我們可以看到蠕蚜,決策邊界改變了。我們甚至可以傳入我們自己的徑向基函數(shù)悔橄,如果需要的話:

>>> def test_kernel(X, y):
        """ Test kernel that returns the exponentiation of the dot of the
        X and y matrices.
        This looks an awful lot like the log hazards if you're familiar with survival analysis.    
        """
        return np.exp(np.dot(X, y.T)) 
>>> test_svc = SVC(kernel=test_kernel) 
>>> test_svc.fit(X, y) 
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0, degree=3,
    gamma=0.0,   kernel=<function test_kernel at 0x121fdfb90>,
    max_iter=-1,   probability=False, random_state=None,     
    shrinking=True, tol=0.001,   verbose=False) 

4.6 使用多類分類來歸納

這個(gè)秘籍中靶累,我們會(huì)了解多類分類。取決于你的算法選擇癣疟,你可以輕松地實(shí)現(xiàn)多類分類挣柬,或者定義用于比較的模式。

準(zhǔn)備

在處理線性模型睛挚,例如邏輯回歸時(shí)邪蛔,我們需要使用OneVsRestClassifier。這個(gè)模式會(huì)為每個(gè)類創(chuàng)建一個(gè)分類器扎狱。

操作步驟

首先侧到,我們會(huì)查看一個(gè)決策樹的粗略示例勃教,用于擬合多類的數(shù)據(jù)集。我們之前討論過匠抗,我們可以使用一些分類器獲得多類故源,所以我們僅僅擬合示例來證明它可以工作,然后繼續(xù)汞贸。

其次绳军,我們實(shí)際上將OneVsRestClassifier合并進(jìn)我的模型中:

>>> from sklearn import datasets 
>>> X, y = datasets.make_classification(n_samples=10000, n_classes=3,
                                        n_informative=3)
>>> from sklearn.tree import DecisionTreeClassifier 
>>> dt = DecisionTreeClassifier() 
>>> dt.fit(X, y) 
>>> dt.predict(X) 
array([1, 1, 0, .., 2, 1, 1])

你可以看到,我們能夠以最低努力來擬合分類器矢腻。

現(xiàn)在门驾,讓我們轉(zhuǎn)向多類分類器的案例中。這需要我們導(dǎo)入OneVsRestClassifier多柑。我們也導(dǎo)入LogisticRegression奶是。

>>> from sklearn.multiclass import OneVsRestClassifier 
>>> from sklearn.linear_model import LogisticRegression

現(xiàn)在,我們覆蓋LogisticRegression分類器顷蟆,同時(shí)诫隅,注意我們可以使其并行化。如果我們想知道OneVsRestClassifier分類器如何工作帐偎,它僅僅是訓(xùn)練單獨(dú)的模型逐纬,之后比較它們。所以削樊,我們可以同時(shí)單獨(dú)訓(xùn)練數(shù)據(jù)豁生。

>>> mlr = OneVsRestClassifier(LogisticRegression(), n_jobs=2) 
>>> mlr.fit(X, y) 
>>> mlr.predict(X) 
array([1, 1, 0, ..., 2, 1, 1])

工作原理

如果我們打算快速時(shí)間我們自己的OneVsRestClassifier,應(yīng)該怎么做呢漫贞?

首先甸箱,我們需要構(gòu)造一種方式,來迭代分類迅脐,并為每個(gè)分類訓(xùn)練分類器芍殖。之后,我們首先需要預(yù)測(cè)每個(gè)分類:

>>> import numpy as np 
>>> def train_one_vs_rest(y, class_label):
        y_train = (y == class_label).astype(int)
        return y_train
>>> classifiers = [] 
>>> for class_i in sorted(np.unique(y)):       l = LogisticRegression()
        y_train = train_one_vs_rest(y, class_i)
        l.fit(X, y_train)
        classifiers.append(l) 

好的谴蔑,所以既然我們配置好了 OneVsRest 模式豌骏,我們需要做的所有事情,就是求出每個(gè)數(shù)據(jù)點(diǎn)對(duì)于每個(gè)分類器的可能性隐锭。我們之后將可能性最大的分類賦給數(shù)據(jù)點(diǎn)窃躲。

例如,讓我們預(yù)測(cè)X[0]

for classifier in classifiers 
>>>  print classifier.predict_proba(X[0])

[[ 0.90443776  0.09556224]] 
[[ 0.03701073  0.96298927]] 
[[ 0.98492829  0.01507171]]

你可以看到钦睡,第二個(gè)分類器(下標(biāo)為1)擁有“正”的最大可能性蒂窒,所以我們將這個(gè)點(diǎn)標(biāo)為1

4.7 將 LDA 用于分類

線性判別分析(LDA)嘗試擬合特征的線性組合,來預(yù)測(cè)結(jié)果變量洒琢。LDA 通常用作預(yù)處理步驟秧秉,我們會(huì)在這篇秘籍中涉及這兩種方法。

準(zhǔn)備

這篇秘籍中纬凤,我們會(huì)做這些事情:

  1. 從雅虎獲取股票數(shù)據(jù)

  2. 將其重新排列為我們熟悉的形狀

  3. 創(chuàng)建 LDA 對(duì)象來擬合和預(yù)測(cè)類標(biāo)簽

  4. 給出如何使用 LDA 來降維的示例

操作步驟

這個(gè)例子中福贞,我們就執(zhí)行一種分析撩嚼,類似于 Altman 的 Z 規(guī)范化停士。在他的論文中,Altamn 基于多種金融度量完丽,預(yù)測(cè)了公司兩年內(nèi)的違約可能性恋技。從它的維基頁面中,我們看到了下面這些東西:

T1 = 流動(dòng)資產(chǎn) / 總資產(chǎn)逻族。相對(duì)于公司規(guī)模來度量流動(dòng)資產(chǎn)蜻底。

T2 = 留存收益 / 總資產(chǎn)。度量反映公司年齡和盈利能力的收益率聘鳞。

T3 = 利息和稅前的收益 / 總資產(chǎn)薄辅。度量稅和杠桿系數(shù)之外的運(yùn)作效率。它是運(yùn)作收益抠璃,對(duì)于長期生存非常重要站楚。

T4 = 股權(quán)市值 / 總負(fù)債的賬面價(jià)值。添加市場(chǎng)維度搏嗡,可以將證券價(jià)格波動(dòng)展示為危險(xiǎn)信號(hào)窿春。

T5 = 營業(yè)額 / 總資產(chǎn)〔珊校總資產(chǎn)周轉(zhuǎn)的標(biāo)準(zhǔn)度量(每個(gè)產(chǎn)業(yè)的變化都很大)旧乞。

這段來自維基百科:

[1] Altman, Edward I. (September 1968). ""Financial Ratios, Discriminant Analysis and the Prediction of Corporate Bankruptcy"". Journal of Finance: 189–209.

這個(gè)分析中,我們使用 Pandas 從雅虎抓取一些金融數(shù)據(jù)磅氨。我們嘗試預(yù)測(cè)尺栖,股票是否在六個(gè)月內(nèi)會(huì)漲,基于股票的當(dāng)前屬性烦租。很顯然沒有比 Altman 的 Z 規(guī)范化更精妙的東西了延赌。讓我們使用一些汽車股票:

>>> tickers = ["F", "TM", "GM", "TSLA"] 
>>> from pandas.io import data as external_data 
>>> stock_panel = external_data.DataReader(tickers, "yahoo")

這個(gè)數(shù)據(jù)結(jié)構(gòu)是panel,類似于 OLAP 立方體左权,或者三維的DataFrame皮胡。讓我們看看這些數(shù)據(jù),來熟悉一下收盤價(jià)赏迟,因?yàn)槲覀冊(cè)诒容^時(shí)只考慮它屡贺。

>>> stock_df = stock_panel.Close.dropna() 
>>> stock_df.plot(figsize=(7, 5))

下面是輸出:

好的,所以現(xiàn)在我們需要將每支股票的價(jià)格和它六個(gè)月內(nèi)的價(jià)格比較。如果更高甩栈,置為 1泻仙,否則置為 0。

為此量没,我們只需要將其向前移動(dòng) 180 天并比較:

#this dataframe indicates if the stock was higher in 180 days 
>>> classes = (stock_df.shift(-180) > stock_df).astype(int) 

我們需要做的下一件事玉转,就是展開數(shù)據(jù)集:

>>> X = stock_panel.to_frame() 
>>> classes = classes.unstack() 
>>> classes = classes.swaplevel(0, 1).sort_index() 
>>> classes = classes.to_frame() 
>>> classes.index.names = ['Date', 'minor'] 
>>> data = X.join(classes).dropna() 
>>> data.rename(columns={0: 'is_higher'}, inplace=True) 
>>> data.head() 

輸出如下:

好的,我們現(xiàn)在需要為 SciPy 創(chuàng)建矩陣殴蹄。為此究抓,我們會(huì)使用patsy庫。這是一個(gè)非常棒的庫袭灯,可以用于創(chuàng)建和 R 相似的決策矩陣刺下。

>>> import patsy 
>>> X = patsy.dmatrix("Open + High + Low + Close + Volume +
                       is_higher - 1", data.reset_index(),
                       return_type='dataframe') 
>>> X.head()

輸出如下:

patsy是個(gè)非常強(qiáng)大的包。例如稽荧,假設(shè)我們打算使用第一章的一些預(yù)處理橘茉。在patsy中,可以像 R 一樣姨丈,修改公式相當(dāng)于修改決策矩陣畅卓。這里并不會(huì)這么做,但是如果我們打算將數(shù)據(jù)縮放為均值 0 和標(biāo)準(zhǔn)差 1蟋恬,函數(shù)就是scale(open) + scale(high)翁潘。

太棒了。所以現(xiàn)在我們得到了數(shù)據(jù)集筋现。讓我們訓(xùn)練 LDA 對(duì)象吧唐础。

>>> import pandas as pd 
>>> from sklearn.lda import LDA 
>>> lda = LDA() 
>>> lda.fit(X.ix[:, :-1], X.ix[:, -1]);

我們可以看到,數(shù)據(jù)集的預(yù)測(cè)并不是非常糟糕矾飞。確實(shí)一膨,我們打算使用其他參數(shù)改進(jìn)并測(cè)試模型:

>>> from sklearn.metrics import classification_report 
>>> print classification_report(X.ix[:, -1].values,
                                lda.predict(X.ix[:, :-1]))
             precision     recall    f1-score     support 
0.0               0.63       0.59        0.61        1895
1.0               0.60       0.64        0.62        1833
avg / total       0.61       0.61        0.61        3728 

這些度量以多種方式描述了模型如何擬合數(shù)據(jù)。

  • 對(duì)于precision(準(zhǔn)確率)洒沦,假設(shè)模型預(yù)測(cè)正值豹绪,多大比例這個(gè)是對(duì)的?(TP / (TP + FP)

  • 對(duì)于recall(召回率)申眼,假設(shè)某個(gè)類的狀態(tài)是正確的瞒津,我們選取了多大的比例?由于召回率是搜索問題中的常見度量括尸,所以我用“選取”巷蚪。例如,有一些潛在的網(wǎng)頁和搜索術(shù)語相關(guān)濒翻,也就是返回的比例屁柏。(TP / (TP + FN)

  • f1-score參數(shù)嘗試總結(jié)二者關(guān)系啦膜。(2 * p * r / (p + r)

工作原理

LDA 實(shí)際上非常類似于我們之前做過的聚類。我們從數(shù)據(jù)訓(xùn)練線性模型淌喻。之后僧家,一旦我們擁有了模型,我們嘗試預(yù)測(cè)并比較每個(gè)類的數(shù)據(jù)的可能性裸删。我們選擇更加常見的選項(xiàng)八拱。

LDA 實(shí)際上是 QDA 的簡(jiǎn)化,我們會(huì)在下一節(jié)談到它涯塔。這里肌稻,我們假設(shè)每個(gè)類的協(xié)方差都是一樣的,但是 QDA 中伤塌,這個(gè)假設(shè)是不嚴(yán)格的灯萍≡可以將它們的關(guān)系類比為 KNN 和 GMM每聪。

4.8 使用 QDA - 非線性 LDA

QDA 是一些通用技巧的推廣,例如平方回歸齿风。它只是模型的推廣药薯,能夠擬合更復(fù)雜的模型。但是救斑,就像其它東西那樣童本,當(dāng)混入復(fù)雜性時(shí),就更加困難了脸候。

準(zhǔn)備

我們會(huì)擴(kuò)展上一個(gè)秘籍穷娱,并通過 QDA 對(duì)象查看平方判別分析(QDA)。

我們說過我們會(huì)根據(jù)模型的協(xié)方差做出假設(shè)运沦。這里泵额,我們會(huì)緩和這個(gè)假設(shè)。

操作步驟

QDA 是qda模塊的一個(gè)成員携添。使用下列命令來使用 QDA:

>>> from sklearn.qda import QDA 
>>> qda = QDA()

>>> qda.fit(X.ix[:, :-1], X.ix[:, -1]) 
>>> predictions = qda.predict(X.ix[:, :-1]) 
>>> predictions.sum() 
2812.0

>>> from sklearn.metrics import classification_report 
>>> print classification_report(X.ix[:, -1].values, predictions)

              precision     recall     f1-score     support 
0.0                0.75       0.36        0.49         1895 
1.0                0.57       0.88        0.69         1833 
avg / total        0.66       0.62        0.59         3728

你可以看到嫁盲,總體來說都差不多。如果我們回顧 LDA 秘籍烈掠,我們可以看到羞秤,與 QDA 相比,類 0 有很大變化左敌,類 1 變化很小瘾蛋。

工作原理

我們?cè)谏弦粋€(gè)秘籍中提到過,我們本質(zhì)上在這里比較可能性矫限。所以哺哼,如何比較可能性呢京革?讓我們使用價(jià)格來嘗試對(duì)is_higher分類。

我們假設(shè)收盤價(jià)服從對(duì)數(shù)正態(tài)分布幸斥。為了計(jì)算每個(gè)類的可能性匹摇,我們需要為每個(gè)類創(chuàng)建收盤價(jià)的子集,以及訓(xùn)練集和測(cè)試集甲葬。作為下一章的前瞻廊勃,我們使用內(nèi)建的交叉驗(yàn)證方法:

>>> from sklearn import cross_validation as cv
>>> import scipy.stats as sp
>>> for test, train in cv.ShuffleSplit(len(X.Close), n_iter=1):
        train_set = X.iloc[train]
        train_close = train_set.Close
        
        train_0 = train_close[~train_set.is_higher.astype(bool)]       
        train_1 = train_close[train_set.is_higher.astype(bool)]           
        
        test_set = X.iloc[test]
        test_close = test_set.Close.values

        ll_0 = sp.norm.pdf(test_close, train_0.mean())       
        ll_1 = sp.norm.pdf(test_close, train_1.mean())

我們有了兩個(gè)類的可能性,我們可以比較和分配類:

>>> (ll_0 > ll_1).mean() 
0.15588673621460505

4.9 使用隨機(jī)梯度下降來分類

我們?cè)诘诙轮杏懻撨^经窖,隨機(jī)梯度下降是個(gè)用于訓(xùn)練分類模型的基本技巧坡垫。這兩種技巧之間有一些自然聯(lián)系,因?yàn)槊Q就暗示了這一點(diǎn)画侣。

準(zhǔn)備

在回歸中冰悠,我們最小化了損失函數(shù),它用于懲罰連續(xù)刻度上的不良選擇配乱。但是對(duì)于分類溉卓,我們會(huì)最小化損失函數(shù),它用于乘法兩個(gè)或更多情況搬泥。

操作步驟

首先桑寨,讓我們創(chuàng)建一些基本數(shù)據(jù):

>>> from sklearn import datasets 
>>> X, y = datasets.make_classification() 

然后創(chuàng)建SGDClassifier實(shí)例:

>>> from sklearn import linear_model 
>>> sgd_clf = linear_model.SGDClassifier() 

像往常一樣,我們訓(xùn)練模型:

>>> sgd_clf.fit(X, y) 
SGDClassifier(alpha=0.0001, class_weight=None, epsilon=0.1, eta0=0.0,
              fit_intercept=True, l1_ratio=0.15,
              learning_rate='optimal', loss='hinge', n_iter=5,
              n_jobs=1, penalty='l2', power_t=0.5,
              random_state=None,
              shuffle=False, verbose=0, warm_start=False) 

我們可以設(shè)置class_weight參數(shù)來統(tǒng)計(jì)數(shù)據(jù)集中不平衡的變化總數(shù)忿檩。

Hinge 損失函數(shù)定義為:

max(0, 1 - ty)

這里尉尾,t是真正分類,+1 為一種情況燥透,-1 為另一種情況沙咏。系數(shù)向量記為y,因?yàn)樗菑哪P椭袛M合出來的班套。x是感興趣的值肢藐。這也是一種很好的度量方式。以另外一種形式表述:

t ∈ -1, 1
y = βx + b

4.10 使用樸素貝葉斯來分類數(shù)據(jù)

樸素分頁四是個(gè)非常有意思的模型孽尽。它類似于 KNN窖壕,做了一些假設(shè)來簡(jiǎn)化事實(shí),但是仍然在許多情況下都很好杉女。

準(zhǔn)備

這個(gè)秘籍中瞻讽,我們會(huì)使用樸素貝葉斯來分類文檔。我擁有個(gè)人經(jīng)驗(yàn)的一個(gè)示例就是熏挎,使用會(huì)計(jì)學(xué)中的組成賬戶描述符的單詞速勇,例如應(yīng)付賬款,來判斷它屬于利潤表坎拐、現(xiàn)金流轉(zhuǎn)表烦磁、還是資產(chǎn)負(fù)債表养匈。

基本理念是使用來自帶標(biāo)簽的測(cè)試語料庫中的詞頻,來學(xué)習(xí)文檔的分類都伪。之后呕乎,我們可以將其用在訓(xùn)練集上來嘗試預(yù)測(cè)標(biāo)簽。

我們使用 Sklearn 中的newgroups數(shù)據(jù)集來玩轉(zhuǎn)樸素貝葉斯模型陨晶。這是有價(jià)值的一組數(shù)據(jù)猬仁,所以我們抓取它而不是加載它。我們也將分類限制為rec.autosrec.motorcycles先誉。

>>> from sklearn.datasets import fetch_20newsgroups

>>> categories = ["rec.autos", "rec.motorcycles"] 
>>> newgroups = fetch_20newsgroups(categories=categories)

#take a look 
>>> print "\n".join(newgroups.data[:1]) 
From: gregl@zimmer.CSUFresno.EDU (Greg Lewis) 
Subject: Re: WARNING.....(please read)... 
Keywords: BRICK, TRUCK, DANGER 
Nntp-Posting-Host: zimmer.csufresno.edu 
Organization: CSU Fresno 
Lines: 33

[…]

>>> newgroups.target_names[newgroups.target[:1]] 
'rec.autos' 

既然我們擁有了newgroups湿刽,我們需要將每個(gè)文檔表示為詞頻向量。這個(gè)表示就是樸素貝葉斯名稱的來歷褐耳。模型是“樸素”的诈闺,不按照任何文檔間的單詞協(xié)方差,來對(duì)文檔進(jìn)行分類铃芦。這可以認(rèn)為是可以缺陷雅镊,但是樸素貝葉斯已經(jīng)被證實(shí)相當(dāng)可靠。

我們需要將數(shù)據(jù)處理為詞頻矩陣杨帽。這是個(gè)稀疏矩陣漓穿,當(dāng)某個(gè)單詞出現(xiàn)在文檔中時(shí),這個(gè)單詞就有條目注盈。這個(gè)矩陣可能非常大,就像這樣:

>>> from sklearn.feature_extraction.text import CountVectorizer

>>> count_vec = CountVectorizer() 
>>> bow = count_vec.fit_transform(newgroups.data

這個(gè)矩陣是個(gè)稀疏矩陣叙赚,它的長度是文檔數(shù)量乘以不同單詞的數(shù)量老客。它的值是每個(gè)文檔中每個(gè)單詞的頻率。

>>> bow <1192x19177 sparse matrix of type '<type 'numpy.int64'>'
    with 164296 stored elements in Compressed Sparse Row format> 

我們實(shí)際上需要將矩陣表示為密集數(shù)組震叮,用于樸素貝葉斯對(duì)象胧砰。所以,讓我們將其轉(zhuǎn)換回來苇瓣。

>>> bow = np.array(bow.todense()) 

顯然尉间,多數(shù)元素都是 0,但是我們可能打算重構(gòu)文檔的統(tǒng)計(jì)击罪,作為合理性檢查哲嘲。

>>> words = np.array(count_vec.get_feature_names()) 
>>> words[bow[0] > 0][:5] 
array([u'10pm', u'1qh336innfl5', u'33', u'93740', 
u'___________________________________________________________________'],
dtype='<U79') 

現(xiàn)在,這些就是第一個(gè)文檔的示例了媳禁?讓我們使用下面的命令:

>>> '10pm' in newgroups.data[0].lower() 
True 
>>> '1qh336innfl5' in newgroups.data[0].lower() 
True

操作步驟

好的眠副,所以需要比平常更多的時(shí)間來準(zhǔn)備數(shù)據(jù),因?yàn)槲覀兲幚淼奈谋緮?shù)據(jù)竣稽,并不是能夠像之前的矩陣那樣快速表示囱怕。

但是霍弹,既然我們準(zhǔn)備好了,我們啟動(dòng)分類器來訓(xùn)練我們的模型娃弓。

>>> from sklearn import naive_bayes 
>>> clf = naive_bayes.GaussianNB() 

在我們訓(xùn)練模型之前典格,讓我們將數(shù)據(jù)集劃分為訓(xùn)練集和測(cè)試集。

>>> mask = np.random.choice([True, False], len(bow)) 
>>> clf.fit(bow[mask], newgroups.target[mask]) 
>>> predictions = clf.predict(bow[~mask])

既然我們?cè)谟?xùn)練集訓(xùn)練了模型台丛,之后預(yù)測(cè)測(cè)試集來嘗試判斷文章屬于哪個(gè)分類钝计,讓我們獲取準(zhǔn)確率。

>>> np.mean(predictions == newgroups.target[~mask]) 
0.92446043165467628

工作原理

樸素貝葉斯的基本原理齐佳,就是我們可以根據(jù)特征向量私恬,來估計(jì)數(shù)據(jù)點(diǎn)屬于分類的概率(P(Ci|X))。

這可以使用貝葉斯定期來變形炼吴,來變成特征向量的后驗(yàn)概率(P(X|Ci))本鸣。如果特征向量的概率最大,那么后延估計(jì)就選擇這個(gè)分類硅蹦。

更多

我們也可以將樸素貝葉斯擴(kuò)展來執(zhí)行多類分類荣德。我們不適用高斯可能性,而是使用多項(xiàng)式可能性童芹。

首先涮瞻,讓我們獲取第三個(gè)分類:

>>> from sklearn.datasets import fetch_20newsgroups 
>>> mn_categories = ["rec.autos", "rec.motorcycles",
                     "talk.politics.guns"] 
>>> mn_newgroups = fetch_20newsgroups(categories=mn_categories)

我們需要將這些東西向量化。

>>> mn_bow = count_vec.fit_transform(mn_newgroups.data) 
>>> mn_bow = np.array(mn_bow.todense()) 

讓我們創(chuàng)建為訓(xùn)練集和測(cè)試集創(chuàng)建一個(gè)屏蔽數(shù)組假褪。

>>> mn_mask = np.random.choice([True, False], len(mn_newgroups.data)) 
>>> multinom = naive_bayes.MultinomialNB() 
>>> multinom.fit(mn_bow[mn_mask], mn_newgroups.target[mn_mask])

>>> mn_predict = multinom.predict(mn_bow[~mn_mask]) 
>>> np.mean(mn_predict == mn_newgroups.target[~mn_mask]) 0.96594778660612934 

我們做的很好署咽,完全不會(huì)驚訝。我們?cè)趦蓚€(gè)分類的情況下表現(xiàn)不錯(cuò)生音,由于talk.politics.guns分類和其它兩個(gè)正交宁否,我們應(yīng)該也表現(xiàn)不錯(cuò)。

4.11 標(biāo)簽傳遞缀遍,半監(jiān)督學(xué)習(xí)

標(biāo)簽傳遞是個(gè)半監(jiān)督學(xué)習(xí)技巧慕匠,它利用帶標(biāo)簽和不帶標(biāo)簽的數(shù)據(jù),來了解不帶標(biāo)簽的數(shù)據(jù)域醇。通常台谊,受益于分類算法的數(shù)據(jù)是難以標(biāo)注的。例如譬挚,標(biāo)注數(shù)據(jù)的開銷可能非常大锅铅,所以手動(dòng)標(biāo)注一個(gè)子集邊角高效。也就是說殴瘦,對(duì)于公司雇傭分類學(xué)家來說狠角,存在可能較慢,但是在發(fā)展的支持蚪腋。

準(zhǔn)備

另一個(gè)問題范圍就是截尾數(shù)據(jù)丰歌。你可以想象一種情況姨蟋,其中時(shí)間的邊界會(huì)影響你收集數(shù)據(jù)的能力。也就是說立帖,例如眼溶,你將試驗(yàn)藥物給病人,并測(cè)量它們晓勇。有些時(shí)候堂飞,你能夠測(cè)量藥物的結(jié)果固蚤。如果碰巧足夠快尝丐,但是你可能打算預(yù)測(cè)藥物的結(jié)果,它們的反應(yīng)時(shí)間較慢逐工。這些藥物可能對(duì)一些病人有致命的反應(yīng)描融,并且需要采取救生措施铝噩。

操作步驟

為了表示半監(jiān)督或者截尾數(shù)據(jù),我們需要做一些簡(jiǎn)單的數(shù)據(jù)處理窿克。首先骏庸,我們會(huì)瀏覽一個(gè)簡(jiǎn)單的示例,之后轉(zhuǎn)向一些更加困難的情況年叮。

>>> from sklearn import datasets 
>>> d = datasets.load_iris() 

由于我們會(huì)將數(shù)據(jù)搞亂具被,我們做一個(gè)備份,并向標(biāo)簽名稱數(shù)組的副本添加一個(gè)unlabeled成員只损。它會(huì)使數(shù)據(jù)的識(shí)別變得容易一姿。

>>> X = d.data.copy() 
>>> y = d.target.copy() 
>>> names = d.target_names.copy()
>>> names = np.append(names, ['unlabeled']) 
>>> names 
array(['setosa', 'versicolor', 'virginica', 'unlabeled'],
       dtype='|S10') 

現(xiàn)在使用-1更新y,這就是未標(biāo)注情況的記號(hào)改执。這也是我們將unlabeled添加到末尾的原因啸蜜。

>>> y[np.random.choice([True, False], len(y))] = -1 

我們的數(shù)據(jù)現(xiàn)在擁有一系列負(fù)值(-1),散布在真正數(shù)據(jù)當(dāng)中:

>>> y[:10] 
array([-1, -1, -1, -1,  0,  0, -1, -1,  0, -1])
>>> names[y[:10]] 
array(['unlabeled', 'unlabeled', 'unlabeled', 'unlabeled', 'setosa',
       'setosa', 'unlabeled', 'unlabeled', 'setosa', 'unlabeled'],
       dtype='|S10')

我們顯然擁有一大堆未標(biāo)注的數(shù)據(jù)辈挂,現(xiàn)在的目標(biāo)是使用LabelPropagation來預(yù)測(cè)標(biāo)簽:

>>> from sklearn import semi_supervised 
>>> lp = semi_supervised.LabelPropagation()

>>> lp.fit(X, y)

LabelPropagation(alpha=1, gamma=20, kernel='rbf', max_iter=30,
                 n_neighbors=7, tol=0.001)

>>> preds = lp.predict(X) 
>>> (preds == d.target).mean() 
0.98666666666666669 

并不是太壞。我們使用了所有數(shù)據(jù)裹粤,所以這是一種作弊终蒂。并且,iris數(shù)據(jù)集是個(gè)良好分隔的數(shù)據(jù)集遥诉。

雖然我們完成了拇泣,讓我們看看LabelSpreading,它是LabelPropagation的姐妹類矮锈。我們會(huì)在“工作原理”一節(jié)給出LabelSpreadingLabelPropagation的技術(shù)差異霉翔,但是很容易看出它們及其相似。

>>> ls = semi_supervised.LabelSpreading() 

觀察它的工作原理苞笨,LabelSpreading更加健壯和嘈雜债朵。

>>> ls.fit(X, y) 
LabelSpreading(alpha=0.2, gamma=20, kernel='rbf', max_iter=30,
               n_neighbors=7, tol=0.001)
               
>>> (ls.predict(X) == d.target).mean() 
0.96666666666666667

不要認(rèn)為標(biāo)簽傳播算法丟失了幾個(gè)指標(biāo)子眶,它就表現(xiàn)得更差了。關(guān)鍵是序芦,我們可能提供一些預(yù)測(cè)訓(xùn)練集的能力臭杰,并且適用于更廣泛的環(huán)境。

工作原理

標(biāo)簽傳遞的原理是谚中,創(chuàng)建數(shù)據(jù)點(diǎn)的圖渴杆,每條邊上的權(quán)重為:

wij(θ) = dij / θ^2

這個(gè)算法之后的原理是,數(shù)據(jù)點(diǎn)將它們的標(biāo)簽傳遞給未標(biāo)記的數(shù)據(jù)點(diǎn)宪塔。這個(gè)傳遞部分由邊的權(quán)重決定磁奖。

邊上的權(quán)重可以放在轉(zhuǎn)移概率矩陣中。我們可以迭代來估計(jì)實(shí)際的標(biāo)簽某筐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末比搭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子来吩,更是在濱河造成了極大的恐慌敢辩,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弟疆,死亡現(xiàn)場(chǎng)離奇詭異戚长,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)怠苔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門同廉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柑司,你說我怎么就攤上這事迫肖。” “怎么了攒驰?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵蟆湖,是天一觀的道長。 經(jīng)常有香客問我玻粪,道長隅津,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任劲室,我火速辦了婚禮伦仍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘很洋。我一直安慰自己充蓝,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谓苟,像睡著了一般官脓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娜谊,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天确买,我揣著相機(jī)與錄音,去河邊找鬼纱皆。 笑死湾趾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的派草。 我是一名探鬼主播搀缠,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼近迁!你這毒婦竟也來了艺普?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤鉴竭,失蹤者是張志新(化名)和其女友劉穎歧譬,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搏存,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瑰步,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了璧眠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缩焦。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖责静,靈堂內(nèi)的尸體忽然破棺而出袁滥,到底是詐尸還是另有隱情,我是刑警寧澤灾螃,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布题翻,位于F島的核電站,受9級(jí)特大地震影響腰鬼,放射性物質(zhì)發(fā)生泄漏藐握。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一垃喊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧袜炕,春花似錦本谜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽溜在。三九已至,卻和暖如春他托,著一層夾襖步出監(jiān)牢的瞬間掖肋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來泰國打工赏参, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留志笼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓把篓,卻偏偏與公主長得像纫溃,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子韧掩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容