【问题标题】:Converting statsmodels summary object to Pandas Dataframe将 statsmodels 摘要对象转换为 Pandas Dataframe
【发布时间】:2019-01-14 23:32:06
【问题描述】:

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

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
==============================================================================

我想对显着性水平 0.05 的 P 值进行反向消除。为此,我需要删除 P 值最高的预测变量并再次运行代码。

我想知道是否有办法从摘要对象中提取 P 值,这样我就可以使用条件语句运行循环并找到重要变量,而无需手动重复这些步骤。

谢谢。

【问题讨论】:

  • 接受的答案显示了如何将汇总表转换为 pandas DataFrame。但是,对于p值选择的用例,最好直接使用属性results.pvalues,在第二个答案中也使用了。

标签: python pandas statsmodels


【解决方案1】:

将您的模型拟合存储为变量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

您可以进一步探索results对象的所有属性,通过使用dir()进行打印,然后将它们添加到相应的函数和df中。

【讨论】:

  • 感谢 Michael B 的帮助。
  • 没问题,如果有效,请将答案标记为正确!编码/数据科学快乐!!
  • 超好用的功能!
【解决方案2】:

@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]

【讨论】:

  • 这在使用公式 API 时不起作用。 AttributeError: 'OLSResults' object has no attribute 'tables'
  • 你用的是什么版本?我在 python 3.6.5 上并使用最新版本的 statsmodels,但没有测试旧版本。
  • Python 3.6.5,statsmodels 0.9.0
  • 糟糕 - 忘记总结方法了!感谢您指出了这一点。答案已更新。
  • 我怎么没想到呢?边缘hacky但非常整洁。这是使用csv 方法的替代方法,以防万一它派上用场:pd.read_csv(pd.compat.StringIO(table.as_csv()), index_col=0)
【解决方案3】:

一个简单的解决方案就是一行代码:

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

正如 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 尚未被认为是稳定的,尽管看起来很接近。见this discussion。
  • 也适用于 summary()。这应该是公认的答案
【解决方案4】:

您可以编写如下。这将是一个简单的修复,并且几乎每次都能正常工作。

lr.summary2()

【讨论】:

    【解决方案5】:

    如果您想了解周边信息,请尝试以下操作:

    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)
    

    【讨论】:

      【解决方案6】:

      下面的代码将所有指标放入一个可以按键访问的字典中。中间结果实际上是你可以使用的DataFrame,我没有将系数变成dictionary,但你可以应用类似的方法,但然后深两层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']
      

      【讨论】:

        【解决方案7】:

        我仍然认为没有一个清晰的答案可以完整地捕获查询。这是捕获两个数据帧中所有内容的一种方法(一种用于中间表,一种用于顶部和底部的指标)。

        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
        

        【讨论】:

          【解决方案8】:

          它有效,但我在 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))
          

          【讨论】:

            猜你喜欢
            • 2015-09-15
            • 2017-01-13
            • 1970-01-01
            • 1970-01-01
            • 2014-10-05
            • 2022-07-28
            • 2019-02-04
            • 2017-03-17
            • 2017-03-23
            相关资源
            最近更新 更多