• 13.3 statsmodels介绍
    • 估计线性模型
    • 估计时间序列过程

    13.3 statsmodels介绍

    statsmodels是Python进行拟合多种统计模型、进行统计试验和数据探索可视化的库。Statsmodels包含许多经典的统计方法,但没有贝叶斯方法和机器学习模型。

    statsmodels包含的模型有:

    • 线性模型,广义线性模型和健壮线性模型
    • 线性混合效应模型
    • 方差(ANOVA)方法分析
    • 时间序列过程和状态空间模型
    • 广义矩估计

    下面,我会使用一些基本的statsmodels工具,探索Patsy公式和pandasDataFrame对象如何使用模型接口。

    估计线性模型

    statsmodels有多种线性回归模型,包括从基本(比如普通最小二乘)到复杂(比如迭代加权最小二乘法)的。

    statsmodels的线性模型有两种不同的接口:基于数组和基于公式。它们可以通过API模块引入:

    1. import statsmodels.api as sm
    2. import statsmodels.formula.api as smf

    为了展示它们的使用方法,我们从一些随机数据生成一个线性模型:

    1. def dnorm(mean, variance, size=1):
    2. if isinstance(size, int):
    3. size = size,
    4. return mean + np.sqrt(variance) * np.random.randn(*size)
    5. # For reproducibility
    6. np.random.seed(12345)
    7. N = 100
    8. X = np.c_[dnorm(0, 0.4, size=N),
    9. dnorm(0, 0.6, size=N),
    10. dnorm(0, 0.2, size=N)]
    11. eps = dnorm(0, 0.1, size=N)
    12. beta = [0.1, 0.3, 0.5]
    13. y = np.dot(X, beta) + eps

    这里,我使用了“真实”模型和可知参数beta。此时,dnorm可用来生成正态分布数据,带有特定均值和方差。现在有:

    1. In [66]: X[:5]
    2. Out[66]:
    3. array([[-0.1295, -1.2128, 0.5042],
    4. [ 0.3029, -0.4357, -0.2542],
    5. [-0.3285, -0.0253, 0.1384],
    6. [-0.3515, -0.7196, -0.2582],
    7. [ 1.2433, -0.3738, -0.5226]])
    8. In [67]: y[:5]
    9. Out[67]: array([ 0.4279, -0.6735, -0.0909, -0.4895,-0.1289])

    像之前Patsy看到的,线性模型通常要拟合一个截距。sm.add_constant函数可以添加一个截距的列到现存的矩阵:

    1. In [68]: X_model = sm.add_constant(X)
    2. In [69]: X_model[:5]
    3. Out[69]:
    4. array([[ 1. , -0.1295, -1.2128, 0.5042],
    5. [ 1. , 0.3029, -0.4357, -0.2542],
    6. [ 1. , -0.3285, -0.0253, 0.1384],
    7. [ 1. , -0.3515, -0.7196, -0.2582],
    8. [ 1. , 1.2433, -0.3738, -0.5226]])

    sm.OLS类可以拟合一个普通最小二乘回归:

    1. In [70]: model = sm.OLS(y, X)

    这个模型的fit方法返回了一个回归结果对象,它包含估计的模型参数和其它内容:

    1. In [71]: results = model.fit()
    2. In [72]: results.params
    3. Out[72]: array([ 0.1783, 0.223 , 0.501 ])

    对结果使用summary方法可以打印模型的详细诊断结果:

    1. In [73]: print(results.summary())
    2. OLS Regression Results
    3. ==============================================================================
    4. Dep. Variable: y R-squared: 0.430
    5. Model: OLS Adj. R-squared: 0.413
    6. Method: Least Squares F-statistic: 24.42
    7. Date: Mon, 25 Sep 2017 Prob (F-statistic): 7.44e-12
    8. Time: 14:06:15 Log-Likelihood: -34.305
    9. No. Observations: 100 AIC: 74.61
    10. Df Residuals: 97 BIC: 82.42
    11. Df Model: 3
    12. Covariance Type: nonrobust
    13. ==============================================================================
    14. coef std err t P>|t| [0.025 0.975]
    15. ------------------------------------------------------------------------------
    16. x1 0.1783 0.053 3.364 0.001 0.073 0.283
    17. x2 0.2230 0.046 4.818 0.000 0.131 0.315
    18. x3 0.5010 0.080 6.237 0.000 0.342 0.660
    19. ==============================================================================
    20. Omnibus: 4.662 Durbin-Watson: 2.201
    21. Prob(Omnibus): 0.097 Jarque-Bera (JB): 4.098
    22. Skew: 0.481 Prob(JB): 0.129
    23. Kurtosis: 3.243 Cond. No.
    24. 1.74
    25. ==============================================================================
    26. Warnings:
    27. [1] Standard Errors assume that the covariance matrix of the errors is correctly
    28. specified.

    这里的参数名为通用名x1, x2等等。假设所有的模型参数都在一个DataFrame中:

    1. In [74]: data = pd.DataFrame(X, columns=['col0', 'col1', 'col2'])
    2. In [75]: data['y'] = y
    3. In [76]: data[:5]
    4. Out[76]:
    5. col0 col1 col2 y
    6. 0 -0.129468 -1.212753 0.504225 0.427863
    7. 1 0.302910 -0.435742 -0.254180 -0.673480
    8. 2 -0.328522 -0.025302 0.138351 -0.090878
    9. 3 -0.351475 -0.719605 -0.258215 -0.489494
    10. 4 1.243269 -0.373799 -0.522629 -0.128941

    现在,我们使用statsmodels的公式API和Patsy的公式字符串:

    1. In [77]: results = smf.ols('y ~ col0 + col1 + col2', data=data).fit()
    2. In [78]: results.params
    3. Out[78]:
    4. Intercept 0.033559
    5. col0 0.176149
    6. col1 0.224826
    7. col2 0.514808
    8. dtype: float64
    9. In [79]: results.tvalues
    10. Out[79]:
    11. Intercept 0.952188
    12. col0 3.319754
    13. col1 4.850730
    14. col2 6.303971
    15. dtype: float64

    观察下statsmodels是如何返回Series结果的,附带有DataFrame的列名。当使用公式和pandas对象时,我们不需要使用add_constant。

    给出一个样本外数据,你可以根据估计的模型参数计算预测值:

    1. In [80]: results.predict(data[:5])
    2. Out[80]:
    3. 0 -0.002327
    4. 1 -0.141904
    5. 2 0.041226
    6. 3 -0.323070
    7. 4 -0.100535
    8. dtype: float64

    statsmodels的线性模型结果还有其它的分析、诊断和可视化工具。除了普通最小二乘模型,还有其它的线性模型。

    估计时间序列过程

    statsmodels的另一模型类是进行时间序列分析,包括自回归过程、卡尔曼滤波和其它态空间模型,和多元自回归模型。

    用自回归结构和噪声来模拟一些时间序列数据:

    1. init_x = 4
    2. import random
    3. values = [init_x, init_x]
    4. N = 1000
    5. b0 = 0.8
    6. b1 = -0.4
    7. noise = dnorm(0, 0.1, N)
    8. for i in range(N):
    9. new_x = values[-1] * b0 + values[-2] * b1 + noise[i]
    10. values.append(new_x)

    这个数据有AR(2)结构(两个延迟),参数是0.8和-0.4。拟合AR模型时,你可能不知道滞后项的个数,因此可以用较多的滞后量来拟合这个模型:

    1. In [82]: MAXLAGS = 5
    2. In [83]: model = sm.tsa.AR(values)
    3. In [84]: results = model.fit(MAXLAGS)

    结果中的估计参数首先是截距,其次是前两个参数的估计值:

    1. In [85]: results.params
    2. Out[85]: array([-0.0062, 0.7845, -0.4085, -0.0136, 0.015 , 0.0143])

    更多的细节以及如何解释结果超出了本书的范围,可以通过statsmodels文档学习更多。