在statsmodels OLS类中使用分类变量

13

我希望使用statsmodels的OLS类来创建一个多元回归模型。考虑以下数据集:

import statsmodels.api as sm
import pandas as pd
import numpy as np

dict = {'industry': ['mining', 'transportation', 'hospitality', 'finance', 'entertainment'],
  'debt_ratio':np.random.randn(5), 'cash_flow':np.random.randn(5) + 90} 

df = pd.DataFrame.from_dict(dict)

x = data[['debt_ratio', 'industry']]
y = data['cash_flow']

def reg_sm(x, y):
    x = np.array(x).T
    x = sm.add_constant(x)
    results = sm.OLS(endog = y, exog = x).fit()
    return results

当我运行以下代码时:
reg_sm(x, y)

I get the following error:

TypeError: '>=' not supported between instances of 'float' and 'str'

我已经尝试将 industry 变量转换为分类变量,但仍然出现错误。我已经没有其他选择了。


1
这是因为“行业”是分类变量,但OLS期望数字(这可以从其源代码中看到)。删除行业,或按行业分组并将OLS应用于每个组。 - bubble
3个回答

20
我也遇到这个问题,有很多列需要处理成分类变量,这让使用“dummify”变得非常烦人。将其转换为字符串对我也没有用。
对于那些想要在不使用onehot编码数据的情况下解决问题的人,R接口提供了一种很好的方法:
import statsmodels.formula.api as smf
import pandas as pd
import numpy as np

dict = {'industry': ['mining', 'transportation', 'hospitality', 'finance', 'entertainment'],
  'debt_ratio':np.random.randn(5), 'cash_flow':np.random.randn(5) + 90} 

df = pd.DataFrame.from_dict(dict)

x = df[['debt_ratio', 'industry']]
y = df['cash_flow']

# NB. unlike sm.OLS, there is "intercept" term is included here
smf.ols(formula="cash_flow ~ debt_ratio + C(industry)", data=df).fit()

Reference: https://www.statsmodels.org/stable/example_formulas.html#categorical-variables


在这种情况下如何使用 cat 特征进行预测? - Manu Sharma
请查看此链接,它应该与此处讨论的相似。 https://www.statsmodels.org/stable/examples/notebooks/generated/predict.html - Dogemore
就我个人而言,我会接受这个答案,因为它更加简洁(而且我不懂R语言)! - Francesco
函数.get_prediction()在这个方法上似乎不起作用。我需要得到置信度/预测区间。是否有一种使用smf r语法来实现这一点的方法? - Ocean Scientist
在最新版本的 statsmodels(v0.12.2)中,.get_prediction() 方法可用。 - Mohammad-Reza Malekpour
否则 model.predict(dataframe) 就可以正常工作。 - SirJohnFranklin

14

通过将数据类型转换为分类类型,您已经朝着正确的方向迈出了一步。然而,一旦您将DataFrame转换为NumPy数组,您将得到一个object数据类型(NumPy数组作为一个整体只有一个统一的数据类型)。这意味着个别值仍然是基础的str类型,而回归模型绝对不会喜欢这种形式。

您可能希望执行的操作是对此特征进行虚拟化处理。与因子化不同,后者实际上将变量视为连续变量,您需要维护某种程度的分类:

>>> import statsmodels.api as sm
>>> import pandas as pd
>>> import numpy as np
>>> np.random.seed(444)
>>> data = {
...     'industry': ['mining', 'transportation', 'hospitality', 'finance', 'entertainment'],
...    'debt_ratio':np.random.randn(5),
...    'cash_flow':np.random.randn(5) + 90
... }
>>> data = pd.DataFrame.from_dict(data)
>>> data = pd.concat((
...     data,
...     pd.get_dummies(data['industry'], drop_first=True)), axis=1)
>>> # You could also use data.drop('industry', axis=1)
>>> # in the call to pd.concat()
>>> data
         industry  debt_ratio  cash_flow  finance  hospitality  mining  transportation
0          mining    0.357440  88.856850        0            0       1               0
1  transportation    0.377538  89.457560        0            0       0               1
2     hospitality    1.382338  89.451292        0            1       0               0
3         finance    1.175549  90.208520        1            0       0               0
4   entertainment   -0.939276  90.212690        0            0       0               0

现在你有了statsmodels可以更好地处理的数据类型。 drop_first 的目的是避免虚拟陷阱

>>> y = data['cash_flow']
>>> x = data.drop(['cash_flow', 'industry'], axis=1)
>>> sm.OLS(y, x).fit()
<statsmodels.regression.linear_model.RegressionResultsWrapper object at 0x115b87cf8>

最后,仅提供一个小提示:尽量避免使用与内置对象类型同名的名称来命名引用,例如dict


5
用公式接口作为替代 Pandas 创建虚拟变量的方法,可以自动通过 Patsy 将字符串类别转换为虚拟变量。 - Josef
@Josef,您能详细说明如何(干净地)做到这一点吗?由于Pandas将任何字符串转换为np.object。当我尝试使用一些列为字符串的DataFrame时,我会得到“ValueError:Pandas数据转换为对象的numpy dtype。请使用np.asarray(data)检查输入数据。” - Dogemore

0

这只是另一个关于分类变量的类似案例,与在芬兰汉肯(Hanken)提供的R语言统计课程相比,它给出了正确的结果。

import wooldridge as woo
import statsmodels.formula.api as smf
import numpy as np

df = woo.dataWoo('beauty')
print(df.describe)

df['abvavg'] = (df['looks']>=4).astype(int) # good looking
df['belavg'] = (df['looks']<=2).astype(int) # bad looking

df_female = df[df['female']==1]
df_male = df[df['female']==0]

results_female = smf.ols(formula = 'np.log(wage) ~ belavg + abvavg',data=df_female).fit()
print(f"FEMALE results, summary \n {results_female.summary()}")

results_male = smf.ols(formula = 'np.log(wage) ~ belavg + abvavg',data=df_male).fit()
print(f"MALE results, summary \n {results_male.summary()}")

致敬,马库斯


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接