《數據分析實戰-托馬茲.卓巴斯》讀書筆記第3章-從樸素貝葉斯分類器到複雜的神經網絡、隨機樹森林

 

python學習筆記-目錄索引php

 

第3章 探索數據html

本章會介紹一些技術,幫助你對一個銀行營銷電話的數據進行分類。你將學習如下主題:
·測試並比較模型
·樸素貝葉斯分類器
·將邏輯迴歸做爲通用分類器使用
·將支持向量機用做分類引擎
·使用決策樹進行分類
·使用隨機森林預測訂閱者
·使用神經網絡對呼叫進行分類

node

3.1導論

本章中,咱們會對一個銀行的營銷電話進行分類,看看一個呼叫會不會帶來一個信用卡業務。本文引用《A Data-Driven Approach to Predict the Success of Bank Telemarketing》中的數據,這本書可在http://archive.ics.uci.edu/ml/datasets/Bank+Marketing上找到。
爲了能在咱們的模型中使用,咱們轉換了數據。數據字典在/Data/Chapter03/bank_contacts_data_dict.txt。


3.2測試並比較模型
獨立安裝 pandas
>pip install pandas
獨立安裝 scikit-learn
>pip install scikit-learn

pandas讓計算你所用模型的性能指標變得極其容易。咱們使用下面的代碼衡量模型的能力(Codes文件夾根目錄下的helper.py文件):python

 1 import sklearn.metrics as mt    
 2 
 3 def printModelSummary(actual, predicted):
 4     '''
 5         Method to print out model summaries
 6     '''
 7     print('Overall accuracy of the model is {0:.2f} percent'\
 8         .format(
 9             (actual == predicted).sum() / \
10             len(actual) * 100))
11     print('Classification report: \n', 
12         mt.classification_report(actual, predicted))
13     print('Confusion matrix: \n', 
14         mt.confusion_matrix(actual, predicted))
15     print('ROC: ', mt.roc_auc_score(actual, predicted))
16     

 原理
首先,咱們從scikit-learn導入了metrics模塊。而後,咱們輸出模型整體上的精確度。這是統計咱們的模型與實際分類一致的次數((actual==predicted).sum()),再除以測試樣本的規模(len(actual)*100)獲得的。這告訴了咱們整體上成功的比例。若是獨立變量的分佈不對稱,那麼這個維度不能用來評估你的模型。
.confusion_matrix方法以一種很清晰的方式衡量咱們的模型——矩陣的每一行表明着模型弄錯(或預測對)的次數:git

/*
Consusion matrix:
{[10154 1816]
[559,946]}
*/

第一行,很明顯一共是10154+1816=11970的實際觀測值,其屬於0這一類。其中,10154是正確預測的數目(咱們把這種狀況稱做true negative,由於這表明着電話並無帶來信用卡業務),1816是錯誤預測的數目(咱們把這種狀況稱做false positive,這類電話被咱們的模型當成了「帶來了信用卡業務」,實際上並無)。

第二行展現了模型成功預測產出的次數:559次錯誤(稱做false negative,電話帶來了信用卡業務,而模型認爲沒有),946次正確(稱做true positive,電話帶來了信用卡業務,與模型的結論一致)。
這些數值可用於計算一些指標。使用.classification_report(...)方法生成這些指標:web


邀月工做室

 
精確率(Precision)衡量的是,當樣本不是正類時,模型不將樣本預測爲正類的能力。這是true positive(946)與全部預測爲正類的數量(1816+946)的比值:這裏是0.34,至關低。也能夠爲負類計算相對應的值:10154/(10154+559)=0.95。整體的精確率是個體精確率的加權平均,權重就是支持度。支持度(Support)是樣本中各分類的實際數目。
召回率(Recall)可被看做模型找出全部正類的能力。這是真陽性對真陽性與假陰性之和的比值:946/(946+559)=0.63。一樣地,能夠用真陰性比上真陰性和假陽性之和,獲得類別0的召回率。整體的召回率是各種別召回率的加權平均,權重是支持度。
綜合評價指標(F1-score)是精確率和召回率的調和平均。即精確率和召回率乘積的兩倍比上它們的和。用這一個指標來衡量模型表現的好壞。
用於評估模型表現的最後一個指標是ROC曲線(Receiver Operating Characteristic)。ROC曲線將模型的表現可視化(對分類的比例不敏感)。換句話說,這條曲線至關於以更多假陽性的代價換取更多真陽性的權衡。咱們對ROC曲線下方的面積更感興趣。通常認爲0.9到1的模型是優秀的,而0.5和0.6這種的則沒什麼價值——這種模型和拋硬幣作決定沒什麼差異。

在helper.py文件中,咱們放了一些後續章節經常使用的輔助過程。使用最多的應該就是timeit(...)裝飾器了。這個裝飾器可用來測量程序的運行時間:算法

def timeit(method):
    '''
    A decorator to time how long it takes to estimate the models
        一個用於估算模塊所需時間的裝飾器
    '''

    def timed(*args, **kw):
        start = time.time()
        result = method(*args, **kw)
        end = time.time()

        print('The method {0} took {1:2.2f} sec to run.' \
              .format(method.__name__, end-start))
        return result

    return timed

這個裝飾器返回的是timed(...)方法,這個方法測量的是一個方法執行過程的結束與開始的時間戳之差。要使用一個裝飾器,咱們將@timeit(或者@hlp.timeit)放在要測量的函數前面。timeit(...)方法惟一的參數,就是傳遞給timed(...)這個內部方法的method。timed(...)方法啓動計時器,執行傳遞進來的函數,再打印出用了多久。
Python中的函數,也是能夠傳遞的對象,和其餘對象(好比int)沒什麼差異。因此,咱們能夠將方法做爲參數傳給另外一個函數,並在內部使用。
關於(Python 3.7的)裝飾器,可參考http://thecodeship.com/patterns/guide-to-python-function-decorators/
參考

強烈推薦Scikit文檔中關於分類器各類指標的部分:
http://scikit-learn.org/stable/modules/model_evaluation.htmlapi

 

3.3樸素貝葉斯分類器

獨立安裝 pandas
>pip install pandas
獨立安裝 scikit-learn
>pip install scikit-learn

樸素貝葉斯分類器是最簡單的分類技術之一。其理論基礎是貝葉斯定理,在一個事件發生的狀況下,求另外一事件發生的機率:
P(A|B)=P(B|A)P(A)/P(B)

也就是說,咱們有電話及通話方的各類特徵(B),要計算電話帶來信用卡業務的機率(A)。這就等價於計算:觀測到的申請信用卡的頻率P(A),乘以過去贊成辦理信用卡的通話方與電話具備這些特徵的頻率P(B|A),比上數據集中這些通話方與電話的頻率P(B)。
本節示例須要裝好pandas和scikit-learn。咱們還要使用helper.py文件,因此你須要NumPy和time模塊。
helper.py文件放在上一級目錄,咱們須要將上一層目錄加到Python的環境變量中,Python會到這些路徑下尋找代碼:bash

# this is needed to load helper from the parent folder
import sys
sys.path.append('..')

# the rest of the imports
import helper as hlp
import pandas as pd
import sklearn.naive_bayes as nb

使用pandas構造樸素貝葉斯分類器只花兩行代碼。但到那一步以前得作點長一些的準備(classification_naiveBayes.py文件):網絡

 1 # the file name of the dataset
 2 r_filename = '../../Data/Chapter03/bank_contacts.csv'
 3 
 4 
 5 # the file name of the dataset
 6 r_filename = '../../Data/Chapter03/bank_contacts.csv'
 7 
 8 # read the data
 9 csv_read = pd.read_csv(r_filename)
10 
11 # split the data into training(訓練集) and testing(測試集)
12 train_x, train_y, \
13 test_x,  test_y, \
14 labels = hlp.split_data(
15     csv_read, y = 'credit_application')
16 
17 # train the model 訓練模型
18 classifier = fitNaiveBayes((train_x, train_y))
19 
20 # classify the unseen data
21 predicted = classifier.predict(test_x)
22 
23 # print out the results
24 hlp.printModelSummary(test_y, predicted)
25 
26 @hlp.timeit
27 def fitNaiveBayes(data):
28     '''
29     Build the Naive Bayes classifier
30         構造樸素貝葉斯分類器
31     '''
32     # create the classifier object 構造一個分類 器對象
33     naiveBayes_classifier = nb.GaussianNB()
34 
35     # fit the model 擬合模型
36     return naiveBayes_classifier.fit(data[0], data[1])

說明:

咱們先從CSV文件讀取數據,這一步你們應該很熟悉了(參見本書1.2節)。接着將數據拆成訓練集和測試集,維持自變量(x)和因變量(y)的分離(參見本書2.8節)。
helper.py腳本的.split_data(...)方法將數據集拆成兩個子集:默認狀況下,2/3的數據用於訓練,1/3的數據用於測試。這個方法是前一章方法略微複雜些的變體。有兩個必需的參數(按順序)是:data和y(因變量)。data參數應是pandas的DataFrame類型,y應傳這個DataFrame中某列的名字。你能夠用x參數傳入一個列名的列表,做爲指定的自變量(默認是選取除y外的全部列)(本章後面會詳細講這塊)。你也能夠給test_size參數傳入一個0到1之間的數,以指定測試數據佔的比例。
拆分完數據集,咱們就能夠構造分類器了。當前技巧和下一個技巧中,咱們將用@hlp.timeit裝飾器給不一樣的模型計時。
咱們使用Scikit的.GaussianNB()方法構建樸素貝葉斯分類器。這個方法不用傳參數。使用.fit(...)方法擬合模型;要傳的第一個參數是自變量的集合,第二個參數是因變量的向量。一旦擬合,咱們就向主程序返回分類器。模型就構建成功。
下面咱們要測試模型。.predict(...)方法處理test_x數據集,將樣本分爲兩個桶:一個是帶來信用卡申請的電話,一個是沒帶來申請的電話。
Scikit中不一樣模型遵循一樣的命名模式;這樣用起來就很方便。後續用到的其餘模型都有.fit(...)和.predict(...)方法,這樣不用修改代碼,也能很方便地測試不一樣的模型。
咱們用以前介紹的printModelSummary(...)方法測試模型的表現(參考本書3.2節)。fitNaiveBayes(...)在平均狀況下,(在個人機器上)花費0.03秒。
在你的機器上,程序運行的時間極可能不一樣。咱們只將這個時間用做與後續介紹的方法進行比較的基準(你也該如此)。

 邀月工做室

樸素貝葉斯在不少機器學習的應用中都有運用。好比,如何分類文本:http://sebastianraschka.com/Articles/2014_naive_bayes_1.html

 3.4將邏輯迴歸做爲通用分類器使用

獨立安裝 pandas
獨立安裝 StatsModels
>pip install StatsModels

/*
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Installing collected packages: patsy, StatsModels
Successfully installed StatsModels-0.10.2 patsy-0.5.1
FINISHED
 */


邏輯迴歸多是第二普遍的迴歸模型(排在線性迴歸以後)。不過它也可用於解決分類問題。
要實踐本技巧,你須要裝好pandas和StatsModels。若是你使用的是Anaconda發行版Python,那麼這兩個模塊都已預裝。咱們引入StatsModels的兩個部分:

import statsmodels.api as sm
import statsmodels.genmod.families.links as fm

前一個容許咱們選取模型,後一個容許咱們指定連接函數。
相似前一招的模式,咱們先導入須要的模塊,讀入數據,拆分數據集。而後調用fitLogisticRegression(...)方法來預測模型(classification_logistic.py文件):

@hlp.timeit
def fitLogisticRegression(data):
    '''
        Build the logistic regression classifier
        構建邏輯迴歸分類器
    '''
    # create the classifier object 建立分類器對象
    logistic_classifier = sm.GLM(data[1], data[0],
        family=sm.families.Binomial(link=fm.logit))

    # fit the data擬合數據
    return logistic_classifier.fit()


StatsModels模塊提供了.GLM(...)方法。GLM表明廣義線性模型(Generalized Linear Model)。廣義線性模型是一族模型,可爲其餘分佈生成一個線性迴歸(偏差項的正態性假設之下)。模型能夠表述爲:
邀月工做室

這裏g是一個連接函數,Xβ是線性等式的集合,E(Y)是因變量的指望(把它當作一個非正態分佈的平均值)。GLM用連接函數將模型與響應變量的分佈關聯起來。
這裏有全部連接函數的列表:http://statsmodels.sourceforge.net/devel/glm.html#links
StatsModels的.GLM(...)方法容許咱們指定不少分佈。在咱們的例子中,應用了二項分佈變量,這種變量只有兩種取值:1表明帶來信用卡申請的電話,0表明沒帶來信用卡申請的電話。這樣咱們就能夠應用.families.Binomial(...)方法。實際上,二項分佈族默認的連接函數就是logit,因此咱們其實不用顯式指定;咱們這樣作,只是爲了在你要用其餘連接函數時,知道怎麼作。
StatsModels中實現的全部模型族列表:http://statsmodels.sourceforge.net/devel/glm.html#families
咱們更熟悉的也許是sigmoid函數,logit函數是其反函數(參見下圖):
邀月工做室
如你所見,邏輯迴歸的輸出只能在0和1之間變化,咱們能夠將其做爲電話轉化爲信用卡申請的機率;一旦高於50%,咱們就認爲更有可能帶來信用卡申請,將其歸爲1,不然就歸爲0。下面的代碼能夠得到這個效果:

# classify the unseen data 對隱藏的數據分類
predicted = classifier.predict(test_x)

# assign the class指定類別
predicted = [1 if elem > 0.5 else 0 for elem in predicted]

# print out the results打印結果
hlp.printModelSummary(test_y, predicted)

咱們使用列表表達式將最終的分類賦給測試數據集。而後,咱們用.printModel Summary(...)方法列出模型的性能表現。邏輯迴歸分類器的表現要比樸素貝葉斯的好,但這是創建在更高的計算代價之上的。
邀月工做室

與樸素貝葉斯分類器相比,咱們付出了高估false positive的代價,獲得的是更好的歸類true positive的能力。
StatsModels的GLM分類器容許咱們打印出關於迴歸的更詳細的結果,以及係數值和它們的統計表現。在分類器上調用的.summary()方法會打印相似下圖(縮略版)的結果:

   Generalized Linear Model Regression Results                  
==============================================================================
Dep. Variable:     credit_application   No. Observations:                27753
Model:                            GLM   Df Residuals:                    27701
Model Family:                Binomial   Df Model:                           51
Link Function:                  logit   Scale:                          1.0000
Method:                          IRLS   Log-Likelihood:                    nan
Date:                Sun, 15 Mar 2020   Deviance:                          nan
Time:                        16:56:57   Pearson chi2:                 1.90e+19
No. Iterations:                   100                                         
Covariance Type:            nonrobust                                         
================================================================================================
                                   coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------------------------
n_age                        -1.937e+13   4.09e+06  -4.74e+06      0.000   -1.94e+13   -1.94e+13
n_duration                    1.091e+16   7.63e+06   1.43e+09      0.000    1.09e+16    1.09e+16
n_pdays                      -8.708e+14   7.45e+06  -1.17e+08      0.000   -8.71e+14   -8.71e+14
n_previous                   -6.625e+12   1.39e+07  -4.76e+05      0.000   -6.63e+12   -6.63e+12
n_emp_var_rate               -3.034e+15   1.91e+07  -1.59e+08      0.000   -3.03e+15   -3.03e+15
n_cons_price_idx              7.766e+15    1.7e+07   4.57e+08      0.000    7.77e+15    7.77e+15
n_cons_conf_idx               2.743e+15   5.39e+06   5.09e+08      0.000    2.74e+15    2.74e+15
n_euribor3m                  -7.989e+15   1.43e+07  -5.57e+08      0.000   -7.99e+15   -7.99e+15
n_nr_employed                 9.976e+15   2.09e+07   4.76e+08      0.000    9.98e+15    9.98e+15
job_admin                    -3.148e+14   1.23e+06  -2.56e+08      0.000   -3.15e+14   -3.15e+14
job_blue_collar              -3.598e+14   1.34e+06  -2.68e+08      0.000    -3.6e+14    -3.6e+14
job_entrepreneur             -3.638e+14   2.19e+06  -1.66e+08      0.000   -3.64e+14   -3.64e+14
job_housemaid                -3.058e+14    2.5e+06  -1.22e+08      0.000   -3.06e+14   -3.06e+14
job_management               -3.439e+14   1.74e+06  -1.98e+08      0.000   -3.44e+14   -3.44e+14
job_retired                  -2.012e+14   2.29e+06  -8.78e+07      0.000   -2.01e+14   -2.01e+14
job_self_employed            -3.907e+14    2.2e+06  -1.78e+08      0.000   -3.91e+14   -3.91e+14
job_services                 -4.108e+14   1.58e+06   -2.6e+08      0.000   -4.11e+14   -4.11e+14
job_student                  -2.723e+14   2.86e+06  -9.53e+07      0.000   -2.72e+14   -2.72e+14
job_technician               -2.846e+14   1.41e+06  -2.01e+08      0.000   -2.85e+14   -2.85e+14
job_unemployed               -2.482e+14   2.47e+06  -1.01e+08      0.000   -2.48e+14   -2.48e+14
job_unknown                  -4.352e+14   4.24e+06  -1.03e+08      0.000   -4.35e+14   -4.35e+14
marital_divorced             -9.426e+14   2.92e+06  -3.23e+08      0.000   -9.43e+14   -9.43e+14
marital_married              -9.485e+14   2.78e+06  -3.42e+08      0.000   -9.48e+14   -9.48e+14
marital_single                -9.31e+14   2.81e+06  -3.32e+08      0.000   -9.31e+14   -9.31e+14
marital_unknown              -1.109e+15   7.48e+06  -1.48e+08      0.000   -1.11e+15   -1.11e+15
edu_basic_4y                 -3.349e+14   2.62e+06  -1.28e+08      0.000   -3.35e+14   -3.35e+14
edu_basic_6y                 -2.782e+14   2.78e+06     -1e+08      0.000   -2.78e+14   -2.78e+14
edu_basic_9y                 -3.374e+14   2.52e+06  -1.34e+08      0.000   -3.37e+14   -3.37e+14
edu_high_school              -2.794e+14   2.47e+06  -1.13e+08      0.000   -2.79e+14   -2.79e+14
edu_illiterate               -1.898e+15   1.59e+07  -1.19e+08      0.000    -1.9e+15    -1.9e+15
edu_professional_course      -3.051e+14   2.59e+06  -1.18e+08      0.000   -3.05e+14   -3.05e+14
edu_university_degree        -2.503e+14   2.46e+06  -1.02e+08      0.000    -2.5e+14    -2.5e+14
edu_unknown                  -2.477e+14   2.92e+06  -8.47e+07      0.000   -2.48e+14   -2.48e+14
default_unknown              -1.301e+14   1.07e+06  -1.22e+08      0.000    -1.3e+14    -1.3e+14
default_yes                  -9.129e+14   4.75e+07  -1.92e+07      0.000   -9.13e+14   -9.13e+14
housing_unknown               1.694e+13   1.34e+06   1.26e+07      0.000    1.69e+13    1.69e+13
housing_yes                  -3.679e+13   8.24e+05  -4.47e+07      0.000   -3.68e+13   -3.68e+13
loan_unknown                  1.694e+13   1.34e+06   1.26e+07      0.000    1.69e+13    1.69e+13
loan_yes                     -1.265e+13   1.13e+06  -1.12e+07      0.000   -1.27e+13   -1.27e+13
contact_cellular              -1.92e+15   3.79e+06  -5.07e+08      0.000   -1.92e+15   -1.92e+15
contact_telephone            -2.011e+15    4.2e+06  -4.79e+08      0.000   -2.01e+15   -2.01e+15
prev_ctc_outcome_failure     -9.593e+14   4.53e+06  -2.12e+08      0.000   -9.59e+14   -9.59e+14
prev_ctc_outcome_nonexistent -7.454e+14   4.15e+06  -1.79e+08      0.000   -7.45e+14   -7.45e+14
prev_ctc_outcome_success     -2.226e+15   4.54e+06   -4.9e+08      0.000   -2.23e+15   -2.23e+15
month_apr                    -9.509e+13   2.48e+06  -3.83e+07      0.000   -9.51e+13   -9.51e+13
month_aug                     3.182e+14   2.51e+06   1.27e+08      0.000    3.18e+14    3.18e+14
month_dec                    -1.189e+15   5.67e+06   -2.1e+08      0.000   -1.19e+15   -1.19e+15
month_jul                    -4.792e+14   2.27e+06  -2.12e+08      0.000   -4.79e+14   -4.79e+14
month_jun                    -2.196e+15   4.82e+06  -4.56e+08      0.000    -2.2e+15    -2.2e+15
month_mar                    -9.509e+14   3.41e+06  -2.79e+08      0.000   -9.51e+14   -9.51e+14
month_may                    -4.898e+14    1.5e+06  -3.26e+08      0.000    -4.9e+14    -4.9e+14
month_nov                     4.175e+14   1.96e+06   2.13e+08      0.000    4.17e+14    4.17e+14
month_oct                     2.752e+14   3.11e+06   8.84e+07      0.000    2.75e+14    2.75e+14
month_sep                     4.585e+14    3.8e+06   1.21e+08      0.000    4.58e+14    4.58e+14
dow_fri                      -8.033e+14    1.8e+06  -4.45e+08      0.000   -8.03e+14   -8.03e+14
dow_mon                      -8.761e+14   1.74e+06  -5.02e+08      0.000   -8.76e+14   -8.76e+14
dow_thu                       -7.73e+14   1.78e+06  -4.34e+08      0.000   -7.73e+14   -7.73e+14
dow_tue                      -7.526e+14   1.74e+06  -4.33e+08      0.000   -7.53e+14   -7.53e+14
dow_wed                       -7.26e+14   1.75e+06  -4.14e+08      0.000   -7.26e+14   -7.26e+14
================================================================================================
View Code


顯而易見,n_age變量是不顯著的,從模型中捨棄也不會丟失多少精度,而n_duration變量,既顯著,又對消費者是否申請信用卡有重大影響。這樣的信息有助於肯定你的模型,並在移除無關(且可能引入偏差的)變量後讓模型更好。

你也可使用Scikit的方法來估計一個邏輯迴歸分類器(classification_logistic_alternative.py文件):

/*
The method fitLogisticRegression took 0.69 sec to run.
Overall accuracy of the model is 91.15 percent
Classification report: 
               precision    recall  f1-score   support

         0.0       0.93      0.98      0.95     12030
         1.0       0.68      0.40      0.50      1522

    accuracy                           0.91     13552
   macro avg       0.80      0.69      0.73     13552
weighted avg       0.90      0.91      0.90     13552

Confusion matrix: 
 [[11743   287]
 [  913   609]]
ROC:  0.6881371909691387
{'n_age': 0.21385522376961028, 'n_duration': 19.191139443277162, 'n_pdays': -0.8673162838021525, 'n_previous': -0.18411649033655933, 'n_emp_var_rate': -4.665790648993948, 'n_cons_price_idx': 2.6226190540263103, 'n_cons_conf_idx': 0.1321457450143668, 'n_euribor3m': 1.2577893320833486, 'n_nr_employed': -1.0950955374646227, 'job_admin': 0.015606031742936122, 'job_blue_collar': -0.22590019775314962, 'job_entrepreneur': -0.07105552322436609, 'job_housemaid': -0.166748843709672, 'job_management': 0.0016511122208341445, 'job_retired': 0.31613911985033627, 'job_self_employed': -0.10302101859015086, 'job_services': -0.14037817943629885, 'job_student': 0.17802965024700726, 'job_technician': -0.017165213063450657, 'job_unemployed': 0.018250921784332092, 'job_unknown': 0.004532611196154809, 'marital_divorced': -0.0283747974255571, 'marital_married': 0.0557151595182598, 'marital_single': 0.13716177614661754, 'marital_unknown': -0.3545616669747635, 'edu_basic_4y': -0.23092212023892777, 'edu_basic_6y': -0.156627551097012, 'edu_basic_9y': -0.22916859893223016, 'edu_high_school': -0.17797495084025308, 'edu_illiterate': 0.7469642970378965, 'edu_professional_course': -0.06316024234627139, 'edu_university_degree': -0.03984420682156178, 'edu_unknown': -0.039326155497083, 'default_unknown': -0.30134284129316585, 'default_yes': 0.0, 'housing_unknown': -0.11542935562620459, 'housing_yes': -0.027745897790976075, 'loan_unknown': -0.11542935562620459, 'loan_yes': 0.03692190860121382, 'contact_cellular': 0.15231778645440006, 'contact_telephone': -0.3423773151898108, 'prev_ctc_outcome_failure': -0.5210489740812024, 'prev_ctc_outcome_nonexistent': -0.12607757606633352, 'prev_ctc_outcome_success': 0.4570670214120743, 'month_apr': -0.1322878780570286, 'month_aug': 0.39290453068094094, 'month_dec': -0.09699979367892911, 'month_jul': -0.017157002315930734, 'month_jun': -0.22287078365578353, 'month_mar': 1.2715744551548396, 'month_may': -0.6823130145064639, 'month_nov': -0.4443492486046949, 'month_oct': -0.08951220175145218, 'month_sep': -0.1690485920009346, 'dow_fri': -0.06432307409320341, 'dow_mon': -0.22305048792318713, 'dow_thu': 0.0069370229422389225, 'dow_tue': -0.004280105768027797, 'dow_wed': 0.09465711610671972}
*/
View Code


儘管這個方法比StatsModels的要快,但這是付出了代價的,它不能評估哪些係數是統計顯著的,或哪些不是;.LogisticRegression(...)分類器不能生成這些統計數據。
這個模型的結果和StatsModels中的相似,比起樸素貝葉斯分類器,都是用召回率換精確率。
下一章節咱們會介紹mlpy,一個機器學習模塊。其也能用於預計線性模型:http://mlpy.sourceforge.net/docs/3.5/liblinear.html


3.5將支持向量機用做分類引擎

支持向量機(Support Vector Machines,SVM)是一族可用於分類和迴歸問題的強大模型。與前面的模型不一樣,其經過所謂的核技巧,將輸入向量隱式地映射到高維的特徵空間,能夠處理高度非線性的問題。更寬泛的SVM的解釋參見:http://www.statsoft.com/Textbook/Support-Vector-Machines

要執行後續的技巧,你須要mlpy(Machine Learning PYthon)。mlpy不在Anaconda中,因此咱們須要手動安裝它。mlpy要求預裝GSL(GNU Scientific Library);有些系統可能已經裝了GSL,因此我推薦先裝mlpy。訪問http://sourceforge.net/projects/mlpy/files/,下載最新資源(mlpy-<version>.tar.gz)。
注意這個地址只有32位,且只支持python3.3。

試着用pip直接安裝:
pip install mlpy

/*
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting mlpy
.........
ERROR: Command errored out with exit status 1: 'd:\tools\python37\python.exe' -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'d:\\Temp\\pip-install-hkwwru7x\\mlpy\\setup.py'"'"'; __file__='"'"'d:\\Temp\\pip-install-hkwwru7x\\mlpy\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'd:\Temp\pip-record-f_wkvunv\install-record.txt' --single-version-externally-managed --compile Check the logs for full command output.
    Running setup.py install for mlpy: finished with status 'error'
FINISHED
 */

 


解決方案:從非官方下載64位mlpy-3.5.0-cp37-cp37m-win_amd64.whl文件,python3.7命令行下手工安裝便可。
下載地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mlpy
注意,本章SVM代碼仍是運行32位可以經過。64位不行
邀月工做室
pip install gsl

/*
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting gsl
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/ee/1e/14d4c4657bc7130b900c65033861ee0db508d2d9206f4223f5da7c855acc/gsl-0.0.3-py3-none-any.whl
Installing collected packages: gsl
Successfully installed gsl-0.0.3
FINISHED
 */


用mlpy構造SVM分類器很簡單。你只要指定SVM的類型和它的核(classification_svm.py文件):

def fitRBFSVM(data):
    '''
    Build the linear SVM classifier
            構建線性SVM分類器
    '''
    # create the classifier object 構建分類器對象
    svm = ml.LibSvm(svm_type='c_svc',
        kernel_type='linear', C=20.0)

    # fit the data應用數據
    svm.learn(data[0],data[1])

    #return the classifier返回分類器
    return svm

原理:首先,咱們加載mlpy。構建模型從調用.LibSvm(...)方法開始。咱們指定的第一個參數是svm_type。c_svc指定的是C支持向量機分類器;C參數補償了偏差項。你也可使用nu_svc參數,nu參數控制了你的樣本中(最多)容許多少錯誤分類,以及你的觀察值中(最少)有多少能成爲支持向量。
顧名思義,kernel_type指定的是核的類型。咱們能夠選擇線性、多項式、RBF(Radial Basis Functions,徑向基函數)或S函數。根據你選擇的核,模型會試着應用直線、多段線或者非線性的形狀,來給咱們的類別作最好的區分。
線性核適用於線性可分的問題,RBF可用於尋找類別之間高度非線性的界限。參考這裏的展現:http://www.cs.cornell.edu/courses/cs578/2003fa/slides_sigir03_tutorial-modified.v3.pdf
指定了模型以後,咱們讓它從數據中學習(.learn(...))支持向量。要使用一個RBF版本的模型,咱們能夠指定svm對象:

  # create the classifier object 構建分類器對象
    svm = ml.LibSvm(svm_type='c_svc', kernel_type='rbf',
        gamma=0.001, C=20.0)

這裏的gamma參數指定了單個支持向量可影響的範圍。你能夠在這裏看看gamma和C參數的關係:http://scikit-learn.org/stable/auto_examples/svm/plot_rbf_parameters.html
目前爲止,介紹的分類方法中,SVM最慢。性能也不如邏輯迴歸分類器。這可不是說邏輯迴歸就是分類問題的萬能解藥了。對於這個特定的數據集,邏輯迴歸的性能比SVM好;對於其餘非線性問題,SVM也許更適合,也許會有優於邏輯迴歸分類器的性能。這也能從咱們的SVM測試中觀察到:線性核SVM的表現優於RBF核SVM:

Tips:

/*
Exception ignored in: 'libsvm.array1d_to_node'
ValueError: Buffer dtype mismatch, expected 'int_t' but got 'long long'
64位能夠安裝,一直編譯不過去,真是見鬼了,懷疑是64位whl有問題,待求證
*/

解決方案:從非官方下載32位mlpy-3.5.0-cp37-cp37m-win32.whl文件,python官網下載32位安裝文件python-3.7.5.exe

/* D:\tools\Python37_32\Scripts>dir
 驅動器 D 中的卷是 Work
 卷的序列號是 9E78-6D56

 D:\tools\Python37_32\Scripts 的目錄

2019-12-16  10:46    <DIR>          .
2019-12-16  10:46    <DIR>          ..
2019-12-16  10:43            93,042 easy_install-3.7.exe
2019-12-16  10:43            93,042 easy_install.exe
2019-12-16  10:46            93,025 f2py.exe
2019-12-16  10:45            93,029 pip.exe
2019-12-16  10:45            93,029 pip3.7.exe
2019-12-16  10:45            93,029 pip3.exe
               6 個文件        558,196 字節
               2 個目錄 183,223,492,608 可用字節

D:\tools\Python37_32\Scripts>pip3.7 install mlpy-3.5.0-cp37-cp37m-win32.whl
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Processing d:\tools\python37_32\scripts\mlpy-3.5.0-cp37-cp37m-win32.whl
Installing collected packages: mlpy
Successfully installed mlpy-3.5.0

D:\tools\Python37_32\Scripts> */
/*
The method fitLinearSVM took 139.84 sec to run.
The method fitRBFSVM took 19.29 sec to run.
Overall accuracy of the model is 90.77 percent
Classification report:
               precision    recall  f1-score   support

         0.0       0.92      0.98      0.95     11967
         1.0       0.64      0.32      0.43      1445

    accuracy                           0.91     13412
   macro avg       0.78      0.65      0.69     13412
weighted avg       0.89      0.91      0.89     13412

Confusion matrix:
 [[11707   260]
 [  978   467]]
ROC:  0.6507284883487261
Overall accuracy of the model is 90.08 percent
Classification report:
               precision    recall  f1-score   support

         0.0       0.91      0.99      0.95     11967
         1.0       0.63      0.20      0.30      1445

    accuracy                           0.90     13412
   macro avg       0.77      0.59      0.62     13412
weighted avg       0.88      0.90      0.88     13412

Confusion matrix:
 [[11797   170]
 [ 1161   284]]
ROC:  0.5911670299783458
*/

Scikit-learn也提供了預測SVM的方法(classification_svm_alternative.py文件):

def fitSVM(data):
    '''
        Build the SVM classifier
    '''
    # create the classifier object
    svm = sv.SVC(kernel='linear', C=20.0)

    # fit the data
    return svm.fit(data[0],data[1])


這個例子中用了線性核,固然,你也可使用RBF(實際上,.SVC(...)方法默認用的就是RBF)。獲得的結果相似,可是要比mlpy快。若是須要的話,你也能夠列出全部支持向量的信息;這些信息存在分類器的.support_vectors屬性裏:

/*
The method fitSVM took 72.45 sec to run.
Overall accuracy of the model is 90.16 percent
Classification report:
               precision    recall  f1-score   support

         0.0       0.92      0.98      0.95     11952
         1.0       0.65      0.32      0.43      1564

    accuracy                           0.90     13516
   macro avg       0.79      0.65      0.69     13516
weighted avg       0.89      0.90      0.89     13516

Confusion matrix:
 [[11690   262]
 [ 1068   496]]
ROC:  0.6476072662345889
[[0.41975309 0.16510777 1.         ... 0.         0.         0.        ]
 [0.27160494 0.41337942 1.         ... 0.         0.         0.        ]
 [0.45679012 0.17141114 1.         ... 0.         0.         0.        ]
 ...
 [0.55555556 0.06689711 1.         ... 1.         0.         0.        ]
 [0.55555556 0.04229362 0.001001   ... 1.         0.         0.        ]
 [0.69135802 0.06791379 1.         ... 0.         0.         0.        ]] 
*/


3.6使用決策樹進行分類

決策樹普遍用於解決分類問題。顧名思義,決策樹是一個樹狀結構,由根節點向外蔓延出分支。在每一個分支(決策)節點,剩餘的數據以是否知足一個具體的決策標準爲依據,劃分爲兩組。這個過程重複進行,直到不能進行進一步的劃分,或者終止(葉子)節點全部的樣本都從屬於同一個類(這時方差最小)。

要實踐本技巧,你須要裝好pandas和Scikit-learn。另外一種方法須要mlpy。

Scikit-learn提供了DecisionTreeClassifier(...)類,咱們能夠用來預測決策樹分類器(classification_decisionTree.py文件):

def fitDecisionTree(data):
    '''
        Build a decision tree classifier
    '''
    # create the classifier object
    tree = sk.DecisionTreeClassifier(min_samples_split=1000)

    # fit the data
    return tree.fit(data[0],data[1])

首先,咱們導入sklearn.tree模塊,這個模塊提供DecisionTreeClassifier(...)類供咱們使用。而後咱們從CSV文件讀入數據,將數據集拆分紅訓練集和測試集。咱們決定只是用全部變量的一個子集。將咱們想用的變量列表做爲x參數傳入咱們的.split\_data(...)方法:

 train_x, train_y, \
test_x,  test_y, \
labels = hlp.split_data(
    csv_read,
    y = 'credit_application',
    x = ['n_duration','n_nr_employed',
        'prev_ctc_outcome_success','n_euribor3m',
        'n_cons_conf_idx','n_age','month_oct',
        'n_cons_price_idx','edu_university_degree','n_pdays',
        'dow_mon','job_student','job_technician',
        'job_housemaid','edu_basic_6y']
)

注意,咱們的.split_data(...)方法不只返回訓練子集和測試子集,也返回各變量的標籤。
如今有了訓練子集和測試子集,咱們能夠應用決策樹了:

# train the model
classifier = fitDecisionTree((train_x, train_y))

DecisionTreeClassifier(...)類有多種操做方式。這裏,咱們僅僅指定每一個決策節點的觀測值不能少於1000個。
DecisionTreeClassifier(...)類的所有參數列表,參見http://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
將模型應用(.fit(...)方法)到數據上以後,咱們能夠將test_x數據集中的觀測值歸類,打印出下面的結果:

/*
The method fitDecisionTree took 0.06 sec to run.
Overall accuracy of the model is 91.26 percent
Classification report:
               precision    recall  f1-score   support

         0.0       0.94      0.96      0.95     12202
         1.0       0.64      0.55      0.59      1585

    accuracy                           0.91     13787
   macro avg       0.79      0.75      0.77     13787
weighted avg       0.91      0.91      0.91     13787

Confusion matrix:
 [[11710   492]
 [  713   872]]
ROC:  0.7549182349482967
0. n_duration: 0.5034721037471864
1. n_nr_employed: 0.3442687149792282
2. prev_ctc_outcome_success: 0.0
3. n_euribor3m: 0.041463681111437736
4. n_cons_conf_idx: 0.03422990519127428
5. n_age: 0.01335144575508925
6. month_oct: 0.009871520358454011
7. n_cons_price_idx: 0.005585809042490998
8. edu_university_degree: 0.0031636326509486726
9. n_pdays: 0.044546262351931966
10. dow_mon: 0.0
11. job_student: 2.661076258790501e-05
12. job_technician: 0.0
13. job_housemaid: 1.5845999849280513e-05
14. edu_basic_6y: 4.468049521049593e-06 */

目前爲止,這是咱們用過的最好的模型,精確率和召回率都很好。樸素貝葉斯雖然有相似的ROC值,其精確率卻差得多(參見樸素貝葉斯分類器)。而預測決策樹分類器只比樸素貝葉斯分類器稍慢。
Scikit也提供了一個頗有用的.export_graphviz(...)方法,讓你能夠以.dot格式保存模型;.dot格式是GraphViz的本地格式:

# and export to a .dot file
sk.export_graphviz(classifier,
    out_file='../../Data/Chapter03/decisionTree/tree.dot')

 
.dot文件本質上是一個文本文件,不便於閱讀。不過,咱們能夠將其可視化。你可使用GraphViz自己,或者,在Linux或Mac OS X上,你隨時可使用dot工具。
GraphViz是一個開源可視化工具。下載地址:http://www.graphviz.org/Download.php
要爲咱們的樹生成一個PDF文件,只需執行下面這行命令:

/*
dot -Tpdf tree.dot -o tree.pdf
*/

dot命令能夠多種格式輸出這棵樹:PNG(-.jpg)或者SVG(Scalable Vector Graphics(可縮放矢量圖形),-Tsvg)等等。
完整的格式列表,參考http://www.graphviz.org/content/output-formats
-o參數指定輸出文件的名字(本例中,tree.pdf)。輸出以下所示(簡略版):

邀月工做室
上圖中,每一個節點都帶有決策樹的重要信息:
邀月工做室

左邊是決策節點,右邊是最終的葉子節點。X[1]指定了咱們樣本中的變量。要追蹤咱們首先拆分的是哪一個變量,咱們能夠打印出變量名,它們在數據集中的位置,以及它們的重要性:

# print out the importance of features
for counter, (nm, label) \
    in enumerate(
        zip(labels, classifier.feature_importances_)
    ):
    print("{0}. {1}: {2}".format(counter, nm,label))

前面的代碼使用了enumerate(...)方法,這個方法返回兩個元素:計數器和元組(nm,label)。zip(...)方法傳入咱們的標籤對象和決策樹分類器的.feature_importances_屬性,建立出一個實體,這個實體將標籤對象中元素與.feature_importances_中的元素根據位置一一對應,即,標籤中的第一個元素對應.feature_importances_中第一個元素。咱們的腳本輸出以下(簡略版):

能夠看到,咱們的X[1]變量其實是n_nr_employed。因此,若是n_nr_employed小於等於0.4690,咱們就會循着樹前往左邊的下一個決策節點;不然,咱們會往右邊走。
決策節點的gini屬性指的是基尼不純度指標。它衡量的是一個隨機選擇的元素被分錯的可能性:越接近0,你就對觀測值沒有被分錯越有信心。
要學習如何計算基尼不純度指標,參考http://people.revoledu.com/kardi/tutorial/Decision Tree/how-to-measure-impurity.htm
決策節點中,samples屬性指的是拆分了多少樣本。即有多少樣本落到葉子節點的每一個類上。
更多

mlpy框架也能幫咱們預測一個決策樹分類器(classification_decisionTree_alternative.py文件):

 import mlpy as ml

@hlp.timeit
def fitDecisionTree(data):
    '''
        Build a decision tree classifier
    '''
    # create the classifier object
    tree = ml.ClassTree(minsize=1000)

    # fit the data
    tree.learn(data[0],data[1])

    # return the classifier
    return tree

如同Scikit的DecisionTreeClassifier,咱們也指定ClassTree(...)這個類的minsize參數。與Scikit相比,ClassTree(...)這個類可供折騰的選項更少,但也能生成一個一樣有效的決策樹分類器:

/* The method fitDecisionTree took 0.71 sec to run.
Overall accuracy of the model is 91.22 percent
D:\tools\Python37\lib\site-packages\sklearn\metrics\_classification.py:1268: UndefinedMetricWarning: Recall and F-score are ill-defined and being set to 0.0 in labels with no true samples. Use `zero_division` parameter to control this behavior.
  _warn_prf(average, modifier, msg_start, len(result))
Classification report:
               precision    recall  f1-score   support

        -1.0       0.00      0.00      0.00         0
         0.0       0.94      0.96      0.95     11942
         1.0       0.65      0.56      0.60      1608

    accuracy                           0.91     13550
   macro avg       0.53      0.51      0.52     13550
weighted avg       0.91      0.91      0.91     13550

Confusion matrix:
 [[    0     0     0]
 [    2 11455   485]
 [    0   703   905]]
ROC:  0.7611356006769036 */


3.7使用隨機森林預測訂閱者

隨機森林屬於集成模型。集成模型秉承的思想就是人多力量大;將多個弱模型(決策樹)聯合起來,獲得一個反映其衆數的預測。參考https://www.stat.berkeley.edu/~breiman/RandomForests/cc_home.htm
要實踐這個技巧,你須要裝好pandas和scikit-learn。
如同前一個例子,scikit提供了構建隨機森林分類器的簡單方式(classification_random Forest.py文件):

 import sklearn.ensemble as en
import sklearn.tree as sk

@hlp.timeit
def fitRandomForest(data):
    '''
        Build a random forest classifier
    '''
    # create the classifier object
    forest = en.RandomForestClassifier(n_jobs=-1,
        min_samples_split=100, n_estimators=10,
        class_weight="auto")

    # fit the data
    return forest.fit(data[0],data[1]) 

原理:首先,咱們導入scikit-learn中的必要模塊,以使用RandomForestClassifier(...)類。讀入數據集,並將其拆成訓練樣本和測試樣本後,咱們預測RandomForestClassifier(...)。
RandomForestClassifier(...)有多個參數,更多信息參考http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html
咱們先指定n_jobs。這是指在估算和預測階段Python應該並行跑多少個任務。若是你的數據集很大,有不少觀測值和特徵,集成模型中要估算數以千計的樹,這個參數會有顯著的影響。然而在咱們的例子中,在-1(任務數對應處理器的核數)和1(單一任務)之間切換不會帶來多大的差別。
和決策樹分類器同樣,min_samples_split參數控制着拆分時決策節點中觀測值的最小數目。n_estimators指定了構建多少個弱模型;咱們的例子中指定了10個,不過若是須要的話,指定幾千個也是能夠的。class_weight參數控制着每一個類的權重。當你的輸入數據中,各個類的頻率高度偏斜時(就像咱們的例子),這個參數就派上用場了。這個參數設成auto,意味着將類的權重設爲頻率的倒數。你能夠本身指定class_weight:這個參數接受{class:weight}形式的字典。
.fit(...)方法能夠接受一個sample_weight參數(咱們的代碼中沒有體現)。這個指定了每一個觀測值的權重;因此,傳入的值得是一個向量(列表),向量的長度要等於數據集的行數。若是有些觀測值由於各類緣由不可信,這個參數就頗有用了;模型中不用丟棄這些觀測值,你只須要指定小一些的權重就能夠了。
估算RandomForestClassifier(...)的時間由多個因素決定:數據集的大小,分類器的數目,和指定的任務數目。咱們的例子中,由配置決定了,其和決策樹分類器相比不會過久。目前爲止,這個模型在召回率和ROC兩個指標上得分最高。精確率不如其餘模型;這個模型生成的false positive比true positive要多:

/*
The method fitRandomForest took 0.30 sec to run.
Overall accuracy of the model is 86.00 percent
Classification report: 
               precision    recall  f1-score   support

         0.0       0.99      0.85      0.92     12058
         1.0       0.43      0.92      0.59      1465

    accuracy                           0.86     13523
   macro avg       0.71      0.88      0.75     13523
weighted avg       0.93      0.86      0.88     13523

Confusion matrix: 
 [[10288  1770]
 [  123  1342]]
ROC:  0.8846252215542966
0. n_duration: 0.4894029629785369
1. n_nr_employed: 0.1316263044033158
2. prev_ctc_outcome_success: 0.04115542029423514
3. n_euribor3m: 0.07878501119397965
4. n_cons_conf_idx: 0.08192032521143604
5. n_age: 0.027459554226413115
6. month_oct: 0.012822570798719032
7. n_cons_price_idx: 0.06255811847948148
8. edu_university_degree: 0.005049798469728383
9. n_pdays: 0.05688625400786597
10. dow_mon: 0.0034728676038600532
11. job_student: 0.003466901827077513
12. job_technician: 0.0023592908732427884
13. job_housemaid: 0.0017758360204634734
14. edu_basic_6y: 0.0012587836116446092

*/

 

Tips:

/* Traceback (most recent call last):
  File "D:\Java2018\practicalDataAnalysis\Codes\Chapter03\classification_randomForest.py", line 45, in <module>
    classifier = fitRandomForest((train_x, train_y))
  File "D:\Java2018\practicalDataAnalysis\helper.py", line 13, in timed
    result = method(*args, **kw)
  File "D:\Java2018\practicalDataAnalysis\Codes\Chapter03\classification_randomForest.py", line 22, in fitRandomForest
    return forest.fit(data[0],data[1])
  File "D:\tools\Python37\lib\site-packages\sklearn\ensemble\_forest.py", line 321, in fit
    y, expanded_class_weight = self._validate_y_class_weight(y)
  File "D:\tools\Python37\lib\site-packages\sklearn\ensemble\_forest.py", line 567, in _validate_y_class_weight
    % self.class_weight)
ValueError: Valid presets for class_weight include "balanced" and "balanced_subsample".Given "auto". */

 
解決方案:參照官方文檔https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html修改成balanced便可。

咱們將全部的樹輸出到/Data/Chapter03/randomForest文件夾。在這個文件夾中,你會發現有個convertToPdf.sh腳本,自動將.dot格式轉成.pdf格式。這個腳本在任何類UNIX環境(Linux、Mac OS X和Cygwin等)下都應該能正常工做。在這個文件夾下輸入下面的命令運行腳本:

./convertToPdf.sh

腳本很簡單:

#/bin/bash
for f in *.dot;
do 
    echo Processing $f;
    dot -Tpdf $f -o ${f%.*}.pdf;
done

接下來,for循環會遍歷全部的.dot文件;每一個文件的名字都存在f變量中。bash腳本里,咱們用$f訪問f變量中存的值。echo命令將咱們當前處理的文件名字打印到屏幕上。而後,咱們用已經熟悉了的dot命令將.dot文件轉成PDF文檔。注意一下咱們是怎麼去掉.dot擴展名,只提取出文件名,加上新格式的.pdf擴展名的。

梯度提高分類器雖然不是隨機森林分類器,但也屬於同一族模型。梯度提高樹的原理和隨機森林很相似——都是將弱模型聯結起來預測分類。不一樣點在於,隨機森林隨機地訓練樹,而梯度提高嘗試的是優化樹的線性組合。
scikit提供了GradientBoostingClassifier(...)類,以應用梯度提高樹(classifier_gradient Boosting.py文件):

import sklearn.ensemble as en

@hlp.timeit
def fitGradientBoosting(data):
    '''
        Build a gradient boosting classier
    '''
    # create the classifier object
    gradBoost = en.GradientBoostingClassifier(
        min_samples_split=100, n_estimators=500)

    # fit the data
    return gradBoost.fit(data[0],data[1])

GradientBoostingClassifier(...)的參數集合相似於RandomForestClassifier(...);咱們也爲一次拆分指定最少的樣本數,並將弱模型的數目指定爲10。
對咱們的數據來講,梯度提高分類器比起隨機森林,在召回率和ROC兩個指標上表現較差,可是在精確率指標上表現更好:

/*
The method fitGradientBoosting took 11.92 sec to run.
Overall accuracy of the model is 91.35 percent
Classification report: 
               precision    recall  f1-score   support

         0.0       0.94      0.97      0.95     11984
         1.0       0.65      0.51      0.57      1525

    accuracy                           0.91     13509
   macro avg       0.79      0.74      0.76     13509
weighted avg       0.91      0.91      0.91     13509

Confusion matrix: 
 [[11567   417]
 [  752   773]]
ROC:  0.7360444253540239
0. n_duration: 0.46196008952421486
1. n_nr_employed: 0.2697341442143176
2. prev_ctc_outcome_success: 0.006951174326559933
3. n_euribor3m: 0.10057168252401916
4. n_cons_conf_idx: 0.04414534932562641
5. n_age: 0.025543351750548025
6. month_oct: 0.0182558540256949
7. n_cons_price_idx: 0.019076218075925366
8. edu_university_degree: 0.0012984467423719616
9. n_pdays: 0.0478102506589297
10. dow_mon: 0.002763907902594316
11. job_student: 0.00040155661288408193
12. job_technician: 0.0005351738521636878
13. job_housemaid: 0.00048743439032264315
14. edu_basic_6y: 0.0004653660738274407
*/


3.8使用神經網絡對呼叫進行分類

人工神經網絡(Artificial Neural Networks,ANN)是模仿生物大腦功能的機器學習模型。神經網絡的一個基本單元是一個叫做神經元的結構。一個神經元有一個或多個輸入和一個細胞體——神經元中的一個部分,彙總輸入信號,經由激活(遷移)函數決定是否(以及如何)傳播至輸出。人工神經元能夠實現多種遷移函數。從一些基本函數,好比階躍函數,僅當知足某個臨界值纔會發送信號;到不對信號作任何改動的線型函數;再到tanh、sigmoid或RBF等非線性函數。
神經元網絡將神經元組織成層。輸入層介於訓練數據集和神經網絡之間,它須要和x變量一樣數目的輸入神經元。隱藏層有不少神經元。這些神經元的輸入端能夠與前一層的一個、多個或全部神經元相連;信號到達下一層以前會由這些聯結加上權重,要麼放大,要麼阻尼。輸出層神經元的數目要與輸出變量的層數相等。在咱們的例子中,因爲依賴變量有兩層:某人是否申請信用卡,因此咱們用了兩個神經元。下面是兩個隱藏層的神經網絡的一個典型佈局:
邀月工做室

神經元網絡的訓練,實際上是神經元之間聯結權重的變動,與每一個神經元激活函數參數的調整。最流行的監督學習範式是偏差反向傳播訓練方法。這個算法計算網絡的輸出與目標變量之間的偏差,而後將偏差反向傳播到前一層,根據特定神經元對輸出的影響,調整聯結和神經元的參數。

要實踐這個技巧,你須要安裝pandas和PyBrain。要安裝PyBrain,執行這些命令:
>pip install pybrain

/* Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting pybrain
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/be/42/b40b64b7163d360425692db2f15a8c1d8fe4a18f1c5626cf7fcb5f5d5fb6/PyBrain-0.3.tar.gz (262kB)
Building wheels for collected packages: pybrain
  Building wheel for pybrain (setup.py): started
  Building wheel for pybrain (setup.py): finished with status 'done'
  Created wheel for pybrain: filename=PyBrain-0.3-cp37-none-any.whl size=399050 sha256=71115d497b1d6adccc940fbf8d9157d24de10e540ab5aa7c78bbec87f3e31dd8
  Stored in directory: C:\Users\tony zhang\AppData\Local\pip\Cache\wheels\40\1f\6f\76fd7bd538d813b220f1f373a57e61bd4611757ce3a3a1b2fb
Successfully built pybrain
Installing collected packages: pybrain
Successfully installed pybrain-0.3
FINISHED
 */


用PyBrain估算一個簡單的神經元網絡至關輕鬆:

import sklearn.naive_bayes as nb

@hlp.timeit
def fitNaiveBayes(data):
    '''
    Build the Naive Bayes classifier
        構造神經元分類器
    '''
    # create the classifier object 構造一個分類 器對象
    naiveBayes_classifier = nb.GaussianNB()

    # fit the model 擬合模型
    return naiveBayes_classifier.fit(data[0], data[1])


首先,咱們從PyBrain載入全部必要的模塊。.structure讓咱們能夠訪問多種激活函數(參考http://pybrain.org/docs/api/structure/modules.html)。.supervised.trainers模塊爲咱們的網絡提供了監督方法(http://pybrain.org/docs/api/supervised/trainers.html)。最後一個,.tools.shortcuts,容許咱們快速構建網絡。
在這個例子中,咱們構建一個簡單的單隱藏層網絡。不過,在作這個以前,咱們要先準備好數據集:

 def prepareANNDataset(data, prob=None):
    '''
        Method to prepare the dataset for ANN training
        and testing
    '''
    # we only import this when preparing ANN dataset
    import pybrain.datasets as dt

    # supplementary method to convert list to tuple
    def extract(row):
        return tuple(row)

    # get the number of inputs and outputs
    inputs = len(data[0].columns)
    outputs = len(data[1].axes) + 1
    if prob == 'regression':
        outputs -= 1

    # create dataset object
    dataset = dt.SupervisedDataSet(inputs, outputs)

    # convert dataframes to lists of tuples
    x = list(data[0].apply(extract, axis=1))
    if prob == 'regression':
        y = [(item) for item in data[1]]
    else:
        y = [(item,abs(item - 1)) for item in data[1]]

    # and add samples to the ANN dataset
    for x_item, y_item in zip(x,y):
        dataset.addSample(x_item, y_item)

    return dataset

咱們假設,輸入數據是兩個元素組成的元組:第一個元素是帶有全部自變量的DataFrame,第二個元素是帶有因變量的pandas序列結構。
你能夠將序列當作一個DataFrame的單列。
在咱們的方法中,咱們首先導入pybrain.datasets。咱們採用這種方式,是爲了當咱們不須要在腳本中使用這方法時,不用將模塊裝載到內存中。
而後咱們決定網絡有多少輸入和輸出。輸入的數量就是咱們輸入數據集的列數。而輸出的數目,如同前面所說,是咱們因變量的層數。咱們用.SupervisedDataSet(...)建立了ANN數據集的骨架。x對象中有全部的輸入觀測值,y對象中有咱們的目標變量;這兩個結構是元組構成的列表。要建立x,咱們用extract(...)方法將數據(以列表傳入)轉換成元組;要構建訓練網絡的數據集,這一步是必要的。咱們使用DataFrame的.apply(...)方法,將.extract(...)方法應用到DataFrame的每一行上。
extract(...)方法只可由prepareANNDataset(...)方法中的對象訪問;你不能在printModel Summary(...)這種方法中使用。
y對象中也有一個元組列表。y中的元組以這種取反的方式建立:若是第一個元素是0,那麼另外一個元素就是1;要達到這樣的效果,咱們使用一個簡單的數學小技巧,(item,abs(item-1)),即,若是客戶不申請信用卡,那麼咱們的目標變量就是0,減去1(獲得-1)並取絕對值(獲得1)。本質上,咱們是給「客戶不申請信用卡」這個事件設置了一個爲真的標誌變量。
這樣過一遍以後,咱們可使用.addSample(...)方法,將觀測值添加到最終的數據集中。.addSample(...)方法接受的參數是輸入和目標變量構成的元組。
既然準備好了數據集,咱們即可以訓練網絡了。咱們的.fitANN(...)方法輸入數據集,先決定輸入和目標神經元的數目;咱們使用SupervisedDataSet輸入和目標對象的.shape屬性來獲取列的數目。
而後建立真正的ANN。咱們使用PyBrain中內建的一個快捷方法:.buildNetwork(...)方法。第一個匿名參數是輸入層神經元的數目,第二個是隱藏層神經元的數目,第三個,在咱們的例子中,是輸出層神經元的數目。
buildNetwork方法可接受任意數目的隱藏層。這個方法將最後一個匿名參數做爲輸出層神經元的數目。
咱們也指定隱藏層和輸出層的激活函數:hiddenclass參數爲隱藏層指定了TanhLayer,outclass參數指定了SoftmaxLayer。tanh函數將輸入壓縮到0和1之間的範圍,曲線形狀和S函數類似。
選取激活函數時,tanh優於S函數,緣由超出了本書範圍。能夠參考這篇論文:http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf
最後一個參數是誤差。設爲true時,細胞體中的求和函數會包括一個訓練時調整的常數項。想一想線性函數的形式:y=AX+b,A是輸入的權重向量,X是輸入變量的向量,b就是誤差。
既然定義好了網絡,咱們便須要指定訓練的機制。咱們使用反向傳播算法訓練網絡。.BackpropTrainer(...)方法接受咱們新建立的網絡做爲第一個參數。而咱們以前建立的數據集是第二個參數。咱們還指定了兩個屬性:詳細模式以追蹤訓練的進度,而且關閉了批量學習。關閉批量學習讓訓練處於在線模式;在線模式在每一次觀測以後都更新權重和神經元的參數。與此相反,批量學習在每次訓練循環(迭代)後纔將更新應用到網絡結構上。
訓練循環,即迭代,是將訓練數據集中全部觀測值在網絡中過一遍的週期。
如今就是要訓練網絡了。在新建立的訓練者對象上,咱們調用.trainUntilConvergence(...)方法。
你能夠用.train()方法訓練一個迭代,也能夠用.trainEpochs(...)方法訓練多個迭代。更多細節參考http://pybrain.org/docs/api/supervised/trainers.html
這個方法一直運行到收斂爲止,此時,再來一次迭代也不會給訓練集或驗證集帶來更好的結果,或者達到了maxEpochs數目。咱們能夠給validationProportion賦值0.25,這意味着咱們用訓練數據集的四分之一來驗證咱們的模型。
驗證數據集是訓練數據集的一個子集,不會用來訓練網絡。ANN訓練的首要目標是將網絡的輸出和目標變量之間的偏差最小化。然而,這樣可能致使這種場景,模型完美適應每個訓練觀測值(也就是說,網絡的偏差爲0),可是不能很好地泛化(參考https://clgiles.ist.psu.edu/papers/AAAI-97.overfitting.hard_to_do.pdf)。因此,爲了不過擬合,網絡追蹤與驗證數據集之間的偏差;當偏差開始增大時,訓練終止。
在咱們的訓練方案中,咱們將continueEpochs設爲3,這樣當訓練者看到與驗證數據集之間的偏差開始上升後,它還會繼續迭代3次才終止。這是考慮到網絡找到了一個局部的最小值,再經一兩個迭代後,偏差會在上升後再次回落。
訓練好網絡以後,咱們如今能夠預測歸類了:

# train the model 訓練模型
classifier = fitNaiveBayes((train_x, train_y))

# classify the unseen data
predicted = classifier.predict(test_x)


.activateOnDataset(...)方法輸入測試數據集,生成一個預測;對測試數據集中的每一個觀測值,網絡激活並生成一個結果。預測的對象如今有兩個值的輸出;咱們想找出最小值的下標,做爲咱們的歸類。咱們使用.argmin(...)方法獲得這個結果。
因爲結構比以前介紹的模型都要複雜,ANN的估算要多花些時間。在咱們的例子中,與以前介紹的SVM模型相比,神經元網絡表現更好,可是顯著地慢:

邀月工做室
另外,以前介紹的模型,咱們能夠分析係數,但對ANN來講卻不容易。除非是一個很簡單的網絡,不然網絡的參數難於解釋。神經網絡常常以黑盒形式使用:給它一個輸入,吐給你一個輸出,但你無法評估它是怎麼作的。
我不是暗示你老是使用更簡單的模型——個人觀點遠非如此。有些領域,設計顯式的模型會比設計和使用ANN要複雜得多,神經元網絡在這些領域已經得到巨大的成功。好比,語音識別和圖像識別的模型,若是採用顯式的方式,要理解模型的每一個組件以及組件如何影響輸出,這會極度複雜。若是這些顯式信息並非必需的,ANN就很好用。
有了PyBrain,咱們能夠構建更復雜的網絡。這個例子中,咱們構建了兩層隱藏層的ANN:

 # create the classifier object
    ann = pb.buildNetwork(inputs_cnt, 
        inputs_cnt * 2,  
        inputs_cnt / 2,
        target_cnt,
        hiddenclass=st.SigmoidLayer,
        outclass=st.SoftmaxLayer,
        bias=True

這個構建的網絡有兩層隱藏層:第一個有20個隱藏神經元,第二個有5個。
建立和估算一個更復雜的模型,花費的投資並不會白費——與簡單的相比,估算的時間將近有兩倍,表現還更差

/*
The method fitANN took 794.88 sec to run.
Overall accuracy of the model is 91.17 percent
Classification report: 
               precision    recall  f1-score   support

         0.0       0.94      0.96      0.95     11968
         1.0       0.63      0.52      0.57      1526

    accuracy                           0.91     13494
   macro avg       0.79      0.74      0.76     13494
weighted avg       0.91      0.91      0.91     13494

Confusion matrix: 
 [[11513   455]
 [  736   790]]
ROC:  0.7398376338650557
*/


要解釋神經元網絡多種結構的細節,遠遠超出了本書的範圍。在本技巧的介紹中,咱們試着勾勒出大體結構,這樣你會對模型原理有一個更好的理解。要是有讀者對人工神經元網絡感興趣,又有數學功底,原做者強烈推薦閱讀Simon O.Harkin的《Neural Networks and Learning Machines》,http://www.amazon.com/Neural-Networks-Learning-Machines-Edition/dp/0131471392

 

第3 章完。

 python學習筆記-目錄索引

 

隨書源碼官方下載:
http://www.hzcourse.com/web/refbook/detail/7821/92

相關文章
相關標籤/搜索