第十三篇 Python建模庫介紹


前面已經介紹了Python數據分析的編程基礎。數據分析師和科學家總是在數據規整和准備上花費⼤量時間,前面部分的重點在於掌握這些功能。

開發模型選⽤什么庫取決於應⽤本身。許多統計問題可以⽤簡單⽅法解決,⽐如普通的最⼩⼆乘回歸,其它問題可能需要復雜的機器學習⽅法。幸運的是,Python已經成為了運⽤這些分析⽅法的語⾔之⼀,因此讀完這些文章,你可以探索許多⼯具。

本篇中,首先回顧⼀些pandas的特點,在你膠着於pandas數據規整和模型擬合和評分時,它們可能派上⽤場。然后我會簡短介紹兩個流⾏的建模⼯具,statsmodels和scikit-learn。這⼆者每個都值得再寫⼀本書,這里就不做全⾯的介紹,⽽是建議你學習兩個項⽬的線上⽂檔和其它基於Python的數據科學、統計和機器學習的書籍。

一、pandas與模型代碼的接口
模型開發的通常⼯作流程是使⽤pandas進⾏數據加載和清洗,然后切換到建模庫進⾏建模。開發模型的重要⼀環是機器學習中的“特征⼯程”。它可以描述從原始數據集中提取信息的任何數據轉換或分析,這些數據集可能在建模中有⽤。前面學習的數據聚合和GroupBy⼯具常⽤於特征⼯程中

優秀的特征⼯程超出了本書的范圍,我會盡量直⽩地介紹⼀些⽤於數據操作和建模切換的⽅法。

pandas與其它分析庫通常是靠NumPy的數組聯系起來的。將DataFrame轉換為NumPy數組,可以使⽤.values屬性
import numpy as np
import pandas as pd
data = pd.DataFrame({
             'x0': [1, 2, 3, 4, 5],
             'x1': [0.01, -0.01, 0.25, -4.1, 0.],
             'y': [-1.5, 0., 3.6, 1.3, -2.]})
data                    # 輸出如下:
    x0     x1      y
0   1  0.01 -1.5
1   2 -0.01  0.0
2   3  0.25  3.6
3   4 -4.10  1.3
4   5  0.00 -2.0
data.columns            # 輸出:Index(['x0', 'x1', 'y'], dtype='object')
data.values             # 輸出如下:是一個Numpy數組
array([[ 1.  ,  0.01, -1.5 ],
           [ 2.  , -0.01,  0.   ],
           [ 3.  ,  0.25,  3.6 ],
           [ 4.  , -4.1  ,  1.3 ],
           [ 5.  ,  0.    ,  -2.  ]])

要轉換回DataFrame,可以傳遞⼀個⼆維ndarray,可帶有列名
df2 = pd.DataFrame(data.values, columns=['one', 'two', 'three'])
df2                     # 輸出如下:
    one   two  three
0  1.0  0.01   -1.5
1  2.0 -0.01    0.0
2  3.0  0.25    3.6
3  4.0 -4.10    1.3
4  5.0  0.00   -2.0
注意:最好當數據是均勻的時候使⽤.values屬性。例如,全是數值類型。如果數據是不均勻的,結果會是Python對象的ndarray:
df3 = data.copy()
df3['strings'] = ['a', 'b', 'c', 'd', 'e']    # 增加一列非數據列
df3                     # 輸出如下:
    x0     x1     y strings
0   1  0.01 -1.5       a
1   2 -0.01  0.0       b
2   3  0.25  3.6       c
3   4 -4.10  1.3       d
4   5  0.00 -2.0       e
df3.values              # 輸出如下:結果是Python對象的ndarray
array([[1, 0.01, -1.5, 'a'],
           [2, -0.01, 0.0, 'b'],
           [3,  0.25, 3.6, 'c'],
           [4, -4.1,  1.3, 'd'],
           [5,  0.0, -2.0, 'e']], dtype=object)

對於⼀些模型,你可能只想使⽤列的⼦集。我建議你使⽤loc,⽤values作索引
model_cols = ['x0', 'x1']
data.loc[:, model_cols].values      # 選取指定的列,輸出如下:
array([[ 1.  ,  0.01],
           [ 2.  , -0.01],
           [ 3.  ,  0.25],
           [ 4.  , -4.1 ],
           [ 5.  ,  0.   ]])

⼀些庫原⽣⽀持pandas,會⾃動完成⼯作:從DataFrame轉換到NumPy,將模型的參數名添加到輸出表的列或Series。其它情況,你可以⼿⼯進⾏“元數據管理”。

在第12篇,學習了pandas的Categorical類型和pandas.get_dummies函數。假設數據集中有⼀個⾮數值列:
data['category'] = pd.Categorical(['a', 'b', 'a', 'a', 'b'], categories=['a', 'b'])
data
    x0     x1     y category
0   1  0.01 -1.5        a
1   2 -0.01  0.0        b
2   3  0.25  3.6        a
3   4 -4.10  1.3        a
4   5  0.00 -2.0        b

如果我們想替換category列為虛變量,我們可以創建虛變量,刪除category列,然后添加到結果
dummies = pd.get_dummies(data.category, prefix='category')              # get_dummies()的用法參考第七篇第二節第八小節
data_with_dummies = data.drop('category', axis=1).join(dummies)    # 刪除data的category列,並連接dummies的列
data_with_dummies       # 輸出如下:
    x0     x1     y  category_a  category_b
0   1  0.01 -1.5                 1           0
1   2 -0.01  0.0                 0           1
2   3  0.25  3.6                 1           0
3   4 -4.10  1.3                 1           0
4   5  0.00 -2.0                 0           1
⽤虛變量擬合某些統計模型會有⼀些細微差別。當你不只有數字列時,使⽤Patsy(下⼀節的主題)可能更簡單,更不容易出錯。

二、⽤Patsy創建模型描述
Patsy是Python的⼀個庫,使⽤簡短的字符串“公式語法”描述統計模型(尤其是線性模型),可能是受到了R和S統計編程語⾔的公式語法的啟發。

Patsy適合描述statsmodels的線性模型,因此我會關注於它的主要特點,讓你盡快掌握。Patsy的公式是⼀個特殊的字符串語法,如下所示:
y ~ x0 + x1
a+b不是將a與b相加的意思,⽽是為模型創建的設計矩陣patsy.dmatrices函數接收⼀個公式字符串和⼀個數據集(可以是DataFrame或數組的字典),為線性模型創建設計矩陣
data = pd.DataFrame({
             'x0': [1, 2, 3, 4, 5],
             'x1': [0.01, -0.01, 0.25, -4.1, 0.],
             'y': [-1.5, 0., 3.6, 1.3, -2.]})
data                    # 輸出如下:
    x0     x1     y
0   1  0.01 -1.5
1   2 -0.01  0.0
2   3  0.25  3.6
3   4 -4.10  1.3
4   5  0.00 -2.0
import patsy
y, x = patsy.dmatrices('y ~ x0 + x1', data)    # 注意 'y ~ x0 + x1' 是公式字符串,指向data中相應的列名
現在有:
y                       # 輸出如下:
DesignMatrix with shape (5, 1)
      y
   -1.5
    0.0
    3.6
    1.3
   -2.0
   Terms:
     'y' (column 0)
x                       # 輸出如下:
DesignMatrix with shape (5, 3)
   Intercept  x0     x1
                1   1   0.01
                1   2  -0.01
                1   3   0.25
                1   4  -4.10
                1   5   0.00
   Terms:
     'Intercept' (column 0)
     'x0' (column 1)
     'x1' (column 2)
這些Patsy的DesignMatrix實例是NumPy的ndarray,帶有附加元數據
np.asarray(y)           # 輸出如下:
array([[-1.5],
           [ 0. ],
           [ 3.6],
           [ 1.3],
           [-2. ]])
np.asarray(x)           # 輸出如下:
array([[ 1.  ,  1.  ,  0.01],
           [ 1.  ,  2.  , -0.01],
           [ 1.  ,  3.  ,  0.25],
           [ 1.  ,  4.  , -4.1 ],
           [ 1.  ,  5.  ,  0.   ]])
你可能想Intercept是哪⾥來的。這是線性模型(⽐如普通最⼩⼆乘回歸)的慣例⽤法。添加 +0 到模型可以不顯
示intercept:
patsy.dmatrices('y ~ x0 + x1 + 0', data)[1]     # 輸出如下:后面的參數[1]表示取元組的第二個元素
DesignMatrix with shape (5, 2)
   x0     x1
    1   0.01
    2  -0.01
    3   0.25
    4  -4.10
    5   0.00
   Terms:
     'x0' (column 0)
     'x1' (column 1)

Patsy對象可以直接傳遞到算法(⽐如numpy.linalg.lstsq)中,它執⾏普通最⼩⼆乘回歸:
coef, resid, _, _ = np.linalg.lstsq(x, y)

模型的元數據保留在design_info屬性中,因此你可以重新附加列名到擬合系數,以獲得⼀個Series,例如:
coef        # 輸出如下:
array([[ 0.3129],
           [-0.0791],
           [-0.2655]])
coef = pd.Series(coef.squeeze(), index=x.design_info.column_names)
coef        # 輸出如下:
Intercept     0.312910
x0              -0.079106
x1              -0.265464
dtype: float64

1、⽤Patsy公式進⾏數據轉換
可以將Python代碼與patsy公式結合。在評估公式時,庫將嘗試查找在封閉作⽤域內使⽤的函數:
y, x = patsy.dmatrices('y ~ x0 + np.log(np.abs(x1) + 1)', data)
x              # 輸出如下:
DesignMatrix with shape (5, 3)
   Intercept  x0  np.log(np.abs(x1) + 1)
                1   1                 0.00995
                1   2                 0.00995
                1   3                 0.22314
                1   4                 1.62924
                1   5                 0.00000
   Terms:
     'Intercept' (column 0)
     'x0' (column 1)
     'np.log(np.abs(x1) + 1)' (column 2)

常⻅的變量轉換包括標准化(平均值為0,⽅差為1)和中⼼化(減去平均值)。Patsy有內置的函數進⾏這樣的⼯作:
y, X = patsy.dmatrices('y ~ standardize(x0) + center(x1)', data)
X           # 輸出如下:(注意變量名是X)
DesignMatrix with shape (5, 3)
   Intercept  standardize(x0)  center(x1)
           1                 -1.41421        0.78
           1                 -0.70711        0.76
           1                  0.00000        1.02
           1                  0.70711       -3.33
           1                  1.41421        0.77
   Terms:
     'Intercept' (column 0)
     'standardize(x0)' (column 1)
     'center(x1)' (column 2)
作為建模的⼀步,你可能擬合模型到⼀個數據,然后⽤另⼀個數據集評估模型。另⼀個數據集可能是剩余的部分或是新數據。當執⾏中⼼化和標准化轉變,⽤新數據進⾏預測要格外⼩⼼。因為你必須使⽤平均值或標准差轉換新數據集,這也稱作狀態轉換

patsy.build_design_matrices函數可以應⽤於轉換新數據,使⽤原始樣本數據集的保存信息
new_data = pd.DataFrame({
             'x0': [6, 7, 8, 9],
             'x1': [3.1, -0.5, 0, 2.3],
             'y': [1, 2, 3, 4]})
new_X = patsy.build_design_matrices([X.design_info], new_data)          # X在前面已定義,用X的設計模型轉換數據
new_X       # 輸出如下:
[DesignMatrix with shape (4, 3)
    Intercept  standardize(x0)  center(x1)
            1                2.12132        3.87
            1                2.82843        0.27
            1                3.53553        0.77
            1                4.24264        3.07
    Terms:
      'Intercept' (column 0)
      'standardize(x0)' (column 1)
      'center(x1)' (column 2)]

因為Patsy中的加號不是加法的意義,當你按照名稱將數據集的列相加時,你必須⽤特殊 I 函數將它們封裝起來:
y, X = patsy.dmatrices('y~I(x0 + x1)', data)     # 注意是字母(H,I,J 中的 I)
X           # 輸出如下:
DesignMatrix with shape (5, 2)
   Intercept  I(x0 + x1)
           1        1.01
           1        1.99
           1        3.25
           1       -0.10
           1        5.00
   Terms:
     'Intercept' (column 0)
     'I(x0 + x1)' (column 1)
Patsy的patsy.builtins模塊還有⼀些其它的內置轉換。請查看線上⽂檔。
分類數據有⼀個特殊的轉換類,下⾯進⾏講解。

2、分類數據和Patsy
⾮數值數據可以⽤多種⽅式轉換為模型設計矩陣。完整的學習最好和統計課⼀起學習。

當你在Patsy公式中使⽤⾮數值數據,它們會默認轉換為虛變量。如果有截距,會去掉⼀個,避免共線性:
data = pd.DataFrame({
             'key1': ['a', 'a', 'b', 'b', 'a', 'b', 'a', 'b'],
             'key2': [0, 1, 0, 1, 0, 1, 0, 0],
             'v1': [1, 2, 3, 4, 5, 6, 7, 8],
             'v2': [-1, 0, 2.5, -0.5, 4.0, -1.2, 0.2, -1.7]
             })
y, X = patsy.dmatrices('v2~ key1', data)    # data的key1列為非數值數據,默認轉換為虛變量,並且去掉一個
X           # 輸出如下:
DesignMatrix with shape (8, 2)
   Intercept  key1[T.b]
           1          0
           1          0
           1          1
           1          1
           1          0
           1          1
           1          0
           1          1
   Terms:
     'Intercept' (column 0)
     'key1' (column 1)
如果你從模型中忽略截距,每個分類值的列都會包括在設計矩陣的模型中:
y, X = patsy.dmatrices('v2 ~ key1 + 0', data)    # 使用 +0 參數忽略截距,但結果無intercept列
X           # 輸出如下:無intercept列
DesignMatrix with shape (8, 2)
   key1[a]  key1[b]
         1        0
         1        0
         0        1
         0        1
         1        0
         0        1
         1        0
         0        1
   Terms:
     'key1' (columns 0:2)
    
使⽤C函數數值列可以截取為分類量
y, X = patsy.dmatrices('v2 ~ C(key2)', data)     # key2是數值列
X            # 輸出如下:
DesignMatrix with shape (8, 2)
   Intercept  C(key2)[T.1]
           1             0
           1             1
           1             0
           1             1
           1             0
           1             1
           1             0
           1             0
   Terms:
     'Intercept' (column 0)
     'C(key2)' (column 1)

當你在模型中使⽤多個分類名,事情就會變復雜,因為會包括key1:key2形式的相交部分,它可以⽤在⽅差(ANOVA)模型分析中:
data['key2'] = data['key2'].map({0: 'zero', 1: 'one'})    # 把key2列的0映射為 zero,1映射為one
data          # 輸出如下:
   key1  key2  v1   v2
0     a   zero   1 -1.0
1     a    one   2  0.0
2     b   zero   3  2.5
3     b    one   4 -0.5
4     a   zero   5  4.0
5     b    one   6 -1.2
6     a   zero   7  0.2
7     b   zero   8 -1.7
y, X = patsy.dmatrices('v2~ key1 + key2', data)    # key1,key2列都是分類數據,不是數值數據
X           # 輸出如下:
DesignMatrix with shape (8, 3)
   Intercept  key1[T.b]  key2[T.zero]
                1          0             1
                1          0             0
                1          1             1
                1          1             0
                1          0             1
                1          1             0
                1          0             1
                1          1             1
   Terms:
     'Intercept' (column 0)
     'key1' (column 1)
     'key2' (column 2)
y, X = patsy.dmatrices('v2~ key1 + key2 + key1:key2', data)
X           # 輸出如下:(key1:key2表示同時為1時就為1)
DesignMatrix with shape (8, 4)
   Intercept  key1[T.b]  key2[T.zero]  key1[T.b]:key2[T.zero]
                1          0             1                       0
                1          0             0                       0
                1          1             1                       1
                1          1             0                       0
                1          0             1                       0
                1          1             0                       0
                1          0             1                       0
                1          1             1                       1
   Terms:
     'Intercept' (column 0)
     'key1' (column 1)
     'key2' (column 2)
     'key1:key2' (column 3)
Patsy提供轉換分類數據的其它⽅法,包括以特定順序轉換。請參閱線上⽂檔。

三、statsmodels介紹
statsmodels是Python進⾏擬合多種統計模型、進⾏統計試驗和數據探索可視化的庫。Statsmodels包含許多經典的統計⽅法,但沒有⻉葉斯⽅法和機器學習模型。

statsmodels包含的模型有:
             線性模型,⼴義線性模型和健壯線性模型
             線性混合效應模型
             ⽅差(ANOVA)⽅法分析
             時間序列過程和狀態空間模型
             ⼴義矩估計
            
下⾯,使⽤⼀些基本的statsmodels⼯具,探索Patsy公式和pandasDataFrame對象如何使⽤模型接⼝。

1、估計線性模型
statsmodels有多種線性回歸模型,包括從基本(⽐如普通最⼩⼆乘)到復雜(⽐如迭代加權最⼩⼆乘法)的。

statsmodels的線性模型有兩種不同的接⼝:基於數組,和基於公式。它們可以通過API模塊引⼊:
import statsmodels.api as sm
import statsmodels.formula.api as smf

為了展示它們的使⽤⽅法,我們從⼀些隨機數據⽣成⼀個線性模型:
def dnorm(mean, variance, size=1):
        if isinstance(size, int):
             size = size,            # 注意后面的逗號不能少
        return mean + np.sqrt(variance) * np.random.randn(*size)
# For reproducibility
N = 100
X = np.c_[dnorm(0, 0.4, size=N),
                 dnorm(0, 0.6, size=N),
                 dnorm(0, 0.2, size=N)]
eps = dnorm(0, 0.1, size=N)
beta = [0.1, 0.3, 0.5]
y = np.dot(X, beta) + eps
這⾥,我使⽤了“真實”模型和可知參數beta。此時,dnorm可⽤來⽣成正太分布數據,帶有特定均值和⽅差。
現在有:
X[:5]       # 輸出如下:
array([[-0.12946849, -1.21275292,  0.50422488],
          [ 0.30291036, -0.43574176, -0.25417986],
          [-0.32852189, -0.02530153,  0.13835097],
          [-0.35147471, -0.71960511, -0.25821463],
          [ 1.2432688 , -0.37379916, -0.52262905]])
y[:5]       # 輸出如下:
array([ 0.42786349, -0.67348041, -0.09087764, -0.48949442, -0.12894109])

像之前Patsy看到的,線性模型通常要擬合⼀個截距。sm.add_constant函數可以添加⼀個截距的列到現存的矩陣
X_model = sm.add_constant(X)     # 在X矩陣中添加一個截距,新矩陣是X_model
X_model[:5]             # 輸出如下:
array([[ 1.    , -0.1295, -1.2128,  0.5042],
           [ 1.    ,  0.3029, -0.4357, -0.2542],
           [ 1.    , -0.3285, -0.0253,  0.1384],
           [ 1.    , -0.3515, -0.7196, -0.2582],
           [ 1.    ,  1.2433, -0.3738, -0.5226]])

sm.OLS類可以擬合⼀個普通最⼩⼆乘回歸
model = sm.OLS(y, X)
這個模型的fit⽅法返回了⼀個回歸結果對象,它包含估計的模型參數和其它內容
results = model.fit()
results.params          # 輸出:array([0.1783, 0.223 , 0.501 ])

對結果使⽤summary⽅法可以打印模型的詳細診斷結果:
print(results.summary())            # 輸出如下:
                             OLS Regression Results
==============================================================================
Dep. Variable:                                            y   R-squared:                          0.430
Model:                                                  OLS   Adj. R-squared:                   0.413
Method:                                Least Squares   F-statistic:                            24.42
Date:                               Wed, 02 Jan 2019   Prob (F-statistic):            7.44e-12
Time:                                             12:50:34   Log-Likelihood:                -34.305
No. Observations:                                 100   AIC:                                       74.61
Df Residuals:                                           97   BIC:                                       82.42
Df Model:                                                  3
Covariance Type:                        nonrobust
==============================================================================
                     coef     std err             t       P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
x1             0.1783      0.053      3.364      0.001       0.073       0.283
x2             0.2230      0.046      4.818      0.000       0.131       0.315
x3             0.5010      0.080      6.237      0.000       0.342       0.660
==============================================================================
Omnibus:                            4.662   Durbin-Watson:                   2.201
Prob(Omnibus):                  0.097   Jarque-Bera (JB):                 4.098
Skew:                                  0.481   Prob(JB):                              0.129
Kurtosis:                             3.243   Cond. No.                               1.74
==============================================================================
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

這⾥的參數名為原始的名字x1, x2等等。假設所有的模型參數都在⼀個DataFrame中:
data = pd.DataFrame(X, columns=['col0', 'col1', 'col2'])
data['y'] = y
data[:5]                # 輸出如下:
             col0          col1          col2               y
0 -0.129468 -1.212753  0.504225  0.427863
1  0.302910 -0.435742 -0.254180 -0.673480
2 -0.328522 -0.025302  0.138351 -0.090878
3 -0.351475 -0.719605 -0.258215 -0.489494
4  1.243269 -0.373799 -0.522629 -0.128941
現在,我們使⽤statsmodels的公式API和Patsy的公式字符串
results = smf.ols('y ~ col0 + col1 + col2', data=data).fit()
results.params          # 輸出如下:
Intercept    0.033559
col0            0.176149
col1            0.224826
col2            0.514808
dtype: float64
results.tvalues         # 輸出如下:
Intercept    0.952188
col0           3.319754
col1           4.850730
col2           6.303971
dtype: float64
觀察下statsmodels是如何返回Series結果的,附帶有DataFrame的列名。當使⽤公式和pandas對象時,我們不需要使⽤add_constant。

給出⼀個樣本外數據,你可以根據估計的模型參數計算預測值
results.predict(data[:5])           # 輸出如下:
0   -0.002327
1   -0.141904
2    0.041226
3   -0.323070
4   -0.100535
dtype: float64
statsmodels的線性模型結果還有其它的分析、診斷和可視化⼯具。除了普通最⼩⼆乘模型,還有其它的線性模型。

2、估計時間序列過程
statsmodels的另⼀模型類是進⾏時間序列分析包括自回歸過程、卡爾曼濾波和其它態空間模型,和多元自回歸
模型

自回歸結構和噪聲來模擬⼀些時間序列數據:
init_x = 4
import random
values = [init_x, init_x]
N = 1000
b0 = 0.8
b1 = -0.4
noise = dnorm(0, 0.1, N)
for i in range(N):
       new_x = values[-1] * b0 + values[-2] * b1 + noise[i]
       values.append(new_x)
      
這個數據有AR(2)結構(兩個延遲),參數是0.8和-0.4。當你和AR模型,你可能不知道滯后項的個數,因此可以⽤較多的滯后量來擬合這個模型:
MAXLAGS = 5
model = sm.tsa.AR(values)
results = model.fit(MAXLAGS)
結果中的估計參數⾸先是截距,其次是前兩個參數的估計值
results.params          # 輸出如下:
array([-0.0062,  0.7845, -0.4085, -0.0136,  0.015 ,  0.0143])
更多的細節以及如何解釋結果超出了這里的范圍,可以通過statsmodels⽂檔學習更多。

四、scikit-learn介紹
scikit-learn是⼀個⼴泛使⽤、⽤途多樣的Python機器學習庫。它包含多種標准監督和⾮監督機器學習⽅法和模型選擇和評估、數據轉換、數據加載和模型持久化⼯具。這些模型可以⽤於分類、聚合、預測和其它任務

機器學習⽅⾯的學習和應⽤scikit-learn和TensorFlow解決實際問題的線上和紙質資料很多。本小節中,簡要介紹scikit-learnAPI的⻛格。

scikit-learn還沒有和pandas深度結合,但是有些第三⽅包在開發中。盡管如此,pandas⾮常適合在模型擬合前處理數據集。

舉個例⼦,我⽤⼀個Kaggle競賽的經典數據集,關於泰坦尼克號乘客的⽣還率。我們⽤pandas加載測試和訓練數據集:
train = pd.read_csv('datasets/titanic/train.csv')
test = pd.read_csv('datasets/titanic/test.csv')
train[:4]               # 輸出如下:
    PassengerId  Survived  Pclass     \
0                  1              0       3
1                  2              1       1
2                  3              1       3
3                  4              1       1
                                                                                Name            Sex   Age  SibSp       \
0                                                Braund, Mr. Owen Harris          male  22.0      1
1       Cumings, Mrs. John Bradley (Florence Briggs Th...        female  38.0      1
2                                                    Heikkinen, Miss. Laina       female  26.0      0
3                  Futrelle, Mrs. Jacques Heath (Lily May Peel)       female  35.0      1
    Parch                          Ticket           Fare Cabin Embarked
0      0                     A/5 21171       7.2500   NaN        S
1      0                      PC 17599      71.2833   C85         C
2      0      STON/O2. 3101282        7.9250   NaN        S
3      0                          113803      53.1000  C123        S
statsmodels和scikit-learn通常不能接收缺失數據,因此我們要查看列是否包含缺失值
train.isnull().sum()    # 輸出如下:
PassengerId     0
Survived           0
Pclass               0
Name               0
Sex                   0
Age              177
SibSp               0
Parch                0
Ticket               0
Fare                  0
Cabin            687
Embarked         2
dtype: int64
test.isnull().sum()                  # 輸出如下:
PassengerId       0
Pclass                 0
Name                 0
Sex                     0
Age                   86
SibSp                  0
Parch                   0
Ticket                  0
Fare                     1
Cabin               327
Embarked            0
dtype: int64

在統計和機器學習的例⼦中,根據數據中的特征,⼀個典型的任務是預測乘客能否⽣還。模型現在訓練數據集中擬合,然后⽤樣本外測試數據集評估。

我想⽤年齡作為預測值,但是它包含缺失值。缺失數據補全的⽅法有多種,我⽤的是⼀種簡單⽅法,⽤訓練數據集的中位數補全兩個表的空值:
impute_value = train['Age'].median()            # 獲取中位數
train['Age'] = train['Age'].fillna(impute_value)            # 用中位數填充缺失值
test['Age'] = test['Age'].fillna(impute_value)

現在我們需要指定模型。我增加⼀個列IsFemale,作為“Sex”列的編碼
train['IsFemale'] = (train['Sex'] == 'female').astype(int)
test['IsFemale'] = (test['Sex'] == 'female').astype(int)

然后,我們確定⼀些模型變量,並創建NumPy數組:
predictors = ['Pclass', 'IsFemale', 'Age']      # 注意理解下面的步驟
X_train = train[predictors].values
X_test = test[predictors].values
y_train = train['Survived'].values
X_train[:5]              # 輸出如下:
array([[ 3.,  0., 22.],
           [ 1.,  1., 38.],
           [ 3.,  1., 26.],
           [ 1.,  1., 35.],
           [ 3.,  0., 35.]])
y_train[:5]             # 輸出:array([0, 1, 1, 1, 0], dtype=int64)

我不能保證這是⼀個好模型,它的特征都符合。我們⽤scikitlearn的LogisticRegression模型,創建⼀個模型實例:
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()     # 創建模型實例

與statsmodels類似,我們可以⽤model的fit⽅法,將它擬合到訓練數據:
model.fit(X_train, y_train)          # 輸出如下:  
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
           intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
           penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
           verbose=0, warm_start=False)

現在,我們可以⽤model.predict,對測試數據進⾏預測
y_predict = model.predict(X_test)
y_predict[:10]          # 輸出:array([0, 0, 0, 0, 1, 0, 1, 0, 1, 0], dtype=int64)
如果你有測試數據集的真實值,你可以計算准確率或其它錯誤度量值:
(y_true == y_predict).mean()

在實際中,模型訓練經常有許多額外的復雜因素。許多模型有可以調節的參數,有些⽅法(⽐如交叉驗證)可以⽤來進⾏參數調節,避免對訓練數據過擬合。這通常可以提⾼預測性或對新數據的健壯性。

交叉驗證通過分割訓練數據來模擬樣本外預測。基於模型的精度得分(⽐如均⽅差),可以對模型參數進⾏⽹格搜索。有些模型,如logistic回歸,有內置的交叉驗證的估計類。例如,logisticregressioncv類可以⽤⼀個參數指定⽹格搜索對模型的正則化參數C的粒度:
from sklearn.linear_model import LogisticRegressionCV
model_cv = LogisticRegressionCV(10)
model_cv.fit(X_train, y_train)      # 輸出如下:
LogisticRegressionCV(Cs=10, class_weight=None, cv=None, dual=False,
            fit_intercept=True, intercept_scaling=1.0, max_iter=100,
            multi_class='ovr', n_jobs=1, penalty='l2', random_state=None,
            refit=True, scoring=None, solver='lbfgs', tol=0.0001, verbose=0)

要⼿動進⾏交叉驗證,你可以使⽤cross_val_score幫助函數,它可以處理數據分割。例如,要交叉驗證我們的帶有四個不重疊訓練數據的模型,可以這樣做:
from sklearn.model_selection import cross_val_score
model = LogisticRegression(C=10)
scores = cross_val_score(model, X_train, y_train, cv=4)
scores                  # 輸出:array([0.7723, 0.8027, 0.7703, 0.7883])
默認的評分指標取決於模型本身,但是可以明確指定⼀個評分。交叉驗證過的模型需要更⻓時間來訓練,但會有更⾼的模型性能。

五、繼續學習
前面都只是介紹了⼀些Python建模庫的表⾯內容,現在有越來越多的框架⽤於各種統計和機器學習,它們都是⽤Python或Python⽤戶界⾯實現的。

這里的重點是數據規整,有其它的書是關注建模和數據科學⼯具的。其中優秀的有:
Andreas Mueller and Sarah Guido (O’Reilly)的《Introduction to Machine Learning with Python》
Jake VanderPlas (O’Reilly)的 《Python Data Science Handbook》
Joel Grus (O’Reilly) 的 《Data Science from Scratch: First Principles》
Sebastian Raschka (Packt Publishing) 的《Python Machine Learning》
Aurélien Géron (O’Reilly) 的《Hands-On Machine Learning with Scikit-Learn and TensorFlow》
雖然書是學習的好資源,但是隨着底層開源軟件的發展,書的內容會過時。最好是不斷熟悉各種統計和機器學習框架的⽂檔,學習最新的功能和API。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM