【问题标题】:Evaluate slope and error for specific category for statsmodels ols fit为 statsmodels ols fit 评估特定类别的斜率和误差
【发布时间】:2015-06-20 00:12:12
【问题描述】:

我有一个数据框 df,其中包含以下字段:weightlengthanimal。前两个是连续变量,而animal 是一个分类变量,其值为catdogsnake

我想估计体重和长度之间的关系,但这需要以动物的类型为条件,因此我将长度变量与animal 分类变量进行交互。

model = ols(formula='weight ~ length * animal', data=df)
results = model.fit()

如何以编程方式提取重量和长度之间关系的斜率,例如蛇?我了解如何手动执行此操作:将length 的系数添加到animal[T.snake]:length 的系数中。但这有点麻烦和手动,需要我专门处理基本情况,所以我想自动提取这些信息。

此外,我想估计这个斜率的误差。我相信我理解如何通过结合标准误差和协方差来计算这个(更准确地说,执行计算here)。但这比上面的更麻烦,我同样想知道是否有捷径可以提取这些信息。

我的手动计算方法如下。

编辑(2015 年 6 月 22 日):我在下面用于计算错误的原始代码中似乎存在错误。 user333700 的答案中计算的标准误差与我计算的不同,但我没有花时间弄清楚原因。

def get_contained_animal(animals, p):
    # This relies on parameters of the form animal[T.snake]:length.
    for a in animals:
        if a in p:
            return a
    return None

animals = ['cat', 'dog', 'snake']
slopes = {}
errors = {}
for animal in animals:
    slope = 0.
    params = []
    # If this param is related to the length variable and
    # the animal in question, add it to the slope.
    for param, val in results.params.iteritems():
        ac = get_contained_animal(animals, param)
        if (param == 'length' or 
            ('length' in param and 
             ac is None or ac == animal)):
            params.append(param)
            slope += val

    # Calculate the overall error by adding standard errors and 
    # covariances.
    tot_err = 0.
    for i, p1 in enumerate(params):
        tot_err += results.bse[p1]*results.bse[p1]
        for j, p2 in enumerate(params[i:]):
            # add covariance of these parameters
            tot_err += 2*results.cov_params()[p1][p2]

    slopes[animal] = slope
    errors[animal] = tot_err**0.5

此代码可能看起来有点矫枉过正,但在我的实际用例中,我有一个连续变量与两个单独的分类变量交互,每个分类变量都有大量类别(以及模型中我需要忽略的其他术语)用于这些目的)。

【问题讨论】:

  • 对于两个参数之和的情况,标准误差公式看起来是正确的。但是,我认为您没有在与slope 计算相对应的标准错误计算中选择params。此外,除了两个参数的总和之外,这种计算不会轻易推广到其他情况。

标签: python pandas statsmodels


【解决方案1】:

非常简短的背景:

对此的一般问题是,如果我们改变解释变量,保持其他解释变量固定或对这些解释变量取平均值,预测会如何变化。

在非线性离散模型中,有一种特殊的 Margins 方法可以计算这一点,尽管它并未针对分类变量的变化实施。

在线性模型中,预测和预测的变化只是估计参数的线性函数,我们可以(错误地)使用t_test为我们计算效果,它的标准误差和置信区间。

(顺便说一句:statsmodels 正在开发更多辅助方法,以便更轻松地进行这样的预测和边际计算,并且很可能在今年晚些时候推出。)

作为以下代码的简要说明:

  • 我举了一个类似的例子。
  • 我为每种动物类型定义了长度 = 1 或 2 的解释变量
  • 然后,我计算这些解释变量的差异
  • 这定义了可在 t_test 中使用的参数的线性组合或对比。

最后,我与 predict 的结果进行比较,以检查我没有犯任何明显的错误。 (我认为这是正确的,但我写得很快。)

import numpy as np
import pandas as pd

from statsmodels.regression.linear_model import OLS

np.random.seed(2)
nobs = 20
animal_names = np.array(['cat', 'dog', 'snake'])
animal_idx = np.random.random_integers(0, 2, size=nobs)
animal = animal_names[animal_idx]
length = np.random.randn(nobs) + animal_idx
weight = np.random.randn(nobs) + animal_idx + length

data = pd.DataFrame(dict(length=length, weight=weight, animal=animal))

res = OLS.from_formula('weight ~ length * animal', data=data).fit()
print(res.summary())


data_predict1 = data = pd.DataFrame(dict(length=np.ones(3), weight=np.ones(3), 
                                        animal=animal_names))

data_predict2 = data = pd.DataFrame(dict(length=2*np.ones(3), weight=np.ones(3), 
                                        animal=animal_names))

import patsy
x1 = patsy.dmatrix('length * animal', data_predict1)
x2 = patsy.dmatrix('length * animal', data_predict2)

tt = res.t_test(x2 - x1)
print(tt.summary(xname=animal_names.tolist()))

上次打印的结果是

                             Test for Constraints                             
==============================================================================
                 coef    std err          t      P>|t|      [95.0% Conf. Int.]
------------------------------------------------------------------------------
cat            1.0980      0.280      3.926      0.002         0.498     1.698
dog            0.9664      0.860      1.124      0.280        -0.878     2.811
snake          1.5930      0.428      3.720      0.002         0.675     2.511

如果给定动物类型的长度从 1 增加到 2,我们可以通过使用 predict 和比较预测体重的差异来验证结果:

>>> [res.predict({'length': 2, 'animal':[an]}) - res.predict({'length': 1, 'animal':[an]}) for an in animal_names]
[array([ 1.09801656]), array([ 0.96641455]), array([ 1.59301594])]
>>> tt.effect
array([ 1.09801656,  0.96641455,  1.59301594])

注意:我忘记为随机数添加种子,无法复制数字。

【讨论】:

  • 注意:添加种子的编辑不起作用。它需要使用 numpy np.random.seed 而不是 python random 内置包
  • 完全正确——我太懒了。建议进行新的编辑。谢谢!
  • 我从@abeboparebop 的编辑中复制了随机种子的添加和调整后的数字(编辑被审阅者拒绝)
猜你喜欢
  • 2014-07-28
  • 2017-12-17
  • 2016-05-26
  • 2012-07-14
  • 2015-12-31
  • 1970-01-01
  • 1970-01-01
  • 2020-11-23
  • 2023-02-15
相关资源
最近更新 更多