将statsmodels摘要对象转换为Pandas数据框

43

我正在使用statsmodels.formula.api(版本0.9.0)在Windows 10上进行多元线性回归。在拟合模型并使用以下行获取摘要后,我会得到摘要对象格式的摘要。

X_opt  = X[:, [0,1,2,3]]
regressor_OLS = sm.OLS(endog= y, exog= X_opt).fit()
regressor_OLS.summary()


                          OLS Regression Results                            
==============================================================================
Dep. Variable:                      y   R-squared:                       0.951
Model:                            OLS   Adj. R-squared:                  0.948
Method:                 Least Squares   F-statistic:                     296.0
Date:                Wed, 08 Aug 2018   Prob (F-statistic):           4.53e-30
Time:                        00:46:48   Log-Likelihood:                -525.39
No. Observations:                  50   AIC:                             1059.
Df Residuals:                      46   BIC:                             1066.
Df Model:                           3                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const       5.012e+04   6572.353      7.626      0.000    3.69e+04    6.34e+04
x1             0.8057      0.045     17.846      0.000       0.715       0.897
x2            -0.0268      0.051     -0.526      0.602      -0.130       0.076
x3             0.0272      0.016      1.655      0.105      -0.006       0.060
==============================================================================
Omnibus:                       14.838   Durbin-Watson:                   1.282
Prob(Omnibus):                  0.001   Jarque-Bera (JB):               21.442
Skew:                          -0.949   Prob(JB):                     2.21e-05
Kurtosis:                       5.586   Cond. No.                     1.40e+06
==============================================================================

我希望能够进行P值的后向消除,显著性水平为0.05。为此,我需要删除具有最高P值的预测变量并再次运行代码。
我想知道是否有一种方法可以从摘要对象中提取P值,以便我可以运行带有条件语句的循环,并找到显著变量,而不必手动重复这些步骤。
谢谢。

2
被接受的答案展示了如何将摘要表转换为pandas DataFrame。然而,对于基于p值选择的用例,直接使用属性results.pvalues更好,这也是第二个答案中使用的方法。 - Josef
9个回答

66

@Michael B的答案效果不错,但需要“重新创建”表格。实际上,表格本身直接可从summary().tables属性中获取。该属性中的每个表格(它们是一个表格列表)都是SimpleTable,具有输出不同格式的方法。然后我们可以读取任何这些格式作为pd.DataFrame:

import statsmodels.api as sm

model = sm.OLS(y,x)
results = model.fit()
results_summary = results.summary()

# Note that tables is a list. The table at index 1 is the "core" table. Additionally, read_html puts dfs in a list, so we want index 0
results_as_html = results_summary.tables[1].as_html()
pd.read_html(results_as_html, header=0, index_col=0)[0]

2
这在使用公式 API 时不起作用。AttributeError: 'OLSResults' 对象没有属性'tables' - Jan Kislinger
1
你用的是哪个版本?我使用的是Python 3.6.5,并且使用最新版本的statsmodels,但没有测试过旧版本。 - ZaxR
Python 3.6.5,statsmodels 0.9.0 - Jan Kislinger
1
糟糕 - 忘记了摘要方法!感谢指出。答案已更新。 - ZaxR
3
为什么我没想到那个?边缘的技巧,但非常整洁。这里提供一个使用 csv 方法的替代方案,以防有用:pd.read_csv(pd.compat.StringIO(table.as_csv()), index_col=0) - Denziloe
1
自从 pandas>=0.25 版本,已经移除了 pd.compat.StringIO。所以现在需要使用 from io import StringIO。在 pandas==1.2.4 上测试通过! - chicxulub

35
一个简单的解决方案只需要一行代码:
LRresult = (result.summary2().tables[1])
如ZaxR在以下评论中提到的那样,虽然Summary2仍未被认为是稳定的,但它与Summary也能很好地配合使用。因此,这可能是正确的答案:

正如ZaxR在下面的评论中所提到的,尽管Summary2尚未被认为是稳定的,但它与Summary一起运作良好。所以这可能是正确的答案:

LRresult = (result.summary().tables[1])

这将为您提供一个数据框对象:

type(LRresult)

pandas.core.frame.DataFrame

为了获得显著的变量并再次运行测试:

newlist = list(LRresult[LRresult['P>|z|']<=0.05].index)[1:]
myform1 = 'binary_Target' + ' ~ ' + ' + '.join(newlist)

M1_test2 = smf.logit(formula=myform1,data=myM1_1)

result2 = M1_test2.fit(maxiter=200)
LRresult2 = (result2.summary2().tables[1])
LRresult2

Summary2尚未被认为是稳定的,但看起来已经接近了。请参见此讨论 - ZaxR
2
同样适用于summary()。这应该是被接受的答案。 - user3357177
2
@user3357177,不是的。.summary2() 返回的是一个 pandas.DataFrame,而 .summary() 返回的是 statsmodels.SimpleTable - undefined
1
@user3357177,不是的。.summary2() 返回一个 pandas.DataFrame,但是 .summary() 返回 statsmodels.SimpleTable - Amin.A

27

将你的模型拟合结果存储在变量results中,如下所示:

import statsmodels.api as sm
model = sm.OLS(y,x)
results = model.fit()

然后创建一个像下面这样的函数:

def results_summary_to_dataframe(results):
    '''take the result of an statsmodel results table and transforms it into a dataframe'''
    pvals = results.pvalues
    coeff = results.params
    conf_lower = results.conf_int()[0]
    conf_higher = results.conf_int()[1]

    results_df = pd.DataFrame({"pvals":pvals,
                               "coeff":coeff,
                               "conf_lower":conf_lower,
                               "conf_higher":conf_higher
                                })

    #Reordering...
    results_df = results_df[["coeff","pvals","conf_lower","conf_higher"]]
    return results_df

您可以使用dir()打印结果对象的所有属性,然后将它们添加到函数和df中。


感谢Michael B的帮助。 - Sagun Kayastha
没问题,如果它起作用了,请将答案标记为正确!祝编码/数据科学愉快! - Michael B
1
超级有用的函数! - veg2020

3
最初的回答:您可以按照以下方式编写代码。这将是一个简单的修复程序,并且几乎每次都能正常工作。
lr.summary2()

2
我仍然认为没有一个清晰的答案能够完全涵盖此查询。以下是一种使用两个数据框(一个用于中间表,另一个用于顶部和底部的指标)来捕获所有内容的方法。
def reform_df(dft):
    # quick and dirty stacking of cols 2,3 on 0,1
    dfl = dft[[0,1]]
    dfr = dft[[2,3]]
    dfr.columns = 0,1
    dfout = pd.concat([dfl,dfr])
    dfout.columns=['Parameter','Value']
    return dfout

def model_summary_to_dataframe(model):
    # first the middle table      
    results_df = pd.DataFrame(model.summary().tables[1])
    results_df = results_df.set_index(0)
    results_df.columns = results_df.iloc[0]
    results_df = results_df.iloc[1:]
    results_df.index.name='Parameter'

    # now for the surrounding information
    metrics_top = reform_df(pd.DataFrame(model.summary().tables[0]))
    metrics_bot = reform_df(pd.DataFrame(model.summary().tables[2]))
    metrics_df = pd.concat([metrics_top,metrics_bot])

    return pd.DataFrame(results_df),metrics_df

1
下面的代码将所有指标放入一个可通过键访问的字典中。中间结果实际上是一个DataFrame,您可以使用它,我没有将系数转换为字典,但您可以应用类似的方法,然后是两个级别深的dict [var] [metric]。
为了使键易于输入,我将某些指标名称转换为更容易键入的版本。例如,“Prob(Omnibus):”变成prob_omnibus,这样您就可以通过res_dict ['prob_omnibus']访问该值。
import pandas as pd

res = sm.OLS(y, X).fit()
model_results_df = []
coefficient_df = None
for i, tab in enumerate(res.summary().tables):
    header, index_col = None, None
    if i == 1:
        coefficient_df = pd.read_html(tab.as_html(), header=0, index_col=0)[0]
    else:
        df = pd.read_html(tab.as_html())[0]
        model_results_df += [df.iloc[:,0:2], df.iloc[:,2:4]]

model_results_df = pd.DataFrame(np.concatenate(model_results_df), columns=['metric', 'value'])
model_results_df.dropna(inplace=True, axis=0)
model_results_df.metric = model_results_df.metric.apply(lambda x : x.lower().replace(' (', '_')
                                                        .replace('.', '').replace('(', '_')
                                                        .replace(')', '').replace('-', '_')
                                                       .replace(':', '').replace(' ', '_'))

res_dict = dict(zip(model_results_df.metric.values, model_results_df.value.values))
res_dict['f_statistic']

0

这对我有用:

st, data, ss2 = summary_table(result, alpha=0.05)

df = pd.DataFrame( data=data, columns=ss2 )

0

它可以工作,但我发现item[3]中有一个小错误。 这是修复方法:

import pandas as pd
dfs = {}
fs = stepwise_fit.summary()
for item in fs.tables[0].data:
    #print("item " + str(item))
    dfs[item[0].strip()] = item[1].strip()
    dfs[item[2].strip()] = str(item[3]).strip()
for item in fs.tables[2].data:
    dfs[item[0].strip()] = item[1].strip()
    dfs[item[2].strip()] = str(item[3]).strip()
dfs = pd.Series(dfs)
print(type(dfs))

0

如果你想得到周边的信息,请尝试以下方法:

import pandas as pd
dfs = {}
fs = fa_model.summary()
for item in fs.tables[0].data:
    dfs[item[0].strip()] = item[1].strip()
    dfs[item[2].strip()] = item[3].strip()
for item in fs.tables[2].data:
    dfs[item[0].strip()] = item[1].strip()
    dfs[item[2].strip()] = item[3].strip()
dfs = pd.Series(dfs)

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