• 第十三篇 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。

  • 相关阅读:
    [论文收集]Web service security (尤其是RBAC)相关的论文 [更新中]
    [文章摘录] The Case for Cloud Computing (ITPro, 2009)
    [文章摘录] 网络计算系统的分类研究 (计算机学报, 2008)
    文献综述的写法
    [转]VS2005常用快捷键大全
    什么是存储过程
    使用冒泡法对数组排序
    ASP.NET中使用Global.asax文件
    轻松掌握Ajax.net系列教程
    客户端回调实现gridView无刷新分页
  • 原文地址:https://www.cnblogs.com/Micro0623/p/10238394.html
Copyright © 2020-2023  润新知