Fama Macbeth回归Python(熊猫或Statsmodels)

use*_*212 7 python r pandas statsmodels

计量经济学背景

Fama Macbeth回归指的是针对面板数据运行回归的过程(其中存在N个不同的个体并且每个个体对应于多个周期T,例如日,月,年).所以总共有N x T obs.请注意,如果面板数据不平衡,则可以.

Fama Macbeth回归是首先对每个时期进行跨部门的回归,即在给定的时间段内将N个人聚集在一起.为t = 1,...做这个.因此总共运行T回归.然后我们有每个自变量的时间序列系数.然后我们可以使用系数的时间序列进行假设检验.通常我们将平均值作为每个自变量的最终系数.我们使用t-stats来测试重要性.

我的问题

我的问题是在熊猫中实现这一点.从大熊猫的源代码中,我注意到有一个名为的过程fama_macbeth.但我找不到任何关于此的文件.

操作也可以轻松完成groupby.目前我这样做:

def fmreg(data,formula):
    return smf.ols(formula,data=data).fit().params[1]

res=df.groupby('date').apply(fmreg,'ret~var1')
Run Code Online (Sandbox Code Playgroud)

这是有效的,res是一个由系数索引date的系列和系列的值params[1],它是系数var1.但现在我想拥有更多自变量,我需要提取所有这些自变量的系数,但我无法弄清楚.我试过这个

def fmreg(data,formula):
    return smf.ols(formula,data=data).fit().params

res=df.groupby('date').apply(fmreg,'ret~var1+var2+var3')
Run Code Online (Sandbox Code Playgroud)

这不行.期望的结果是,res是由索引的数据帧date,以及数据帧的每列应包含各变量的系数intercept,var1,var2var3.

我也检查过statsmodels,他们也没有这样的内置程序.

是否有任何包可以产生出版品质的回归表?就像outreg2在Stata和texregR?谢谢你的帮助!

Kar*_* D. 8

更新以反映Fama-MacBeth截至2018年秋季的图书馆情况.该fama_macbeth功能现已删除pandas了一段时间.那么你有什么选择呢?

  1. 如果你正在使用python 3,那么您可以使用LinearModels法玛-麦克白方法:https://github.com/bashtage/linearmodels/blob/master/linearmodels/panel/model.py

  2. 如果你正在使用python 2或者只是不想使用LinearModels,那么你可能最好的选择就是自己动手.

例如,假设您在以下面板中拥有Fama-French行业投资组合(您还计算了一些变量,如过去的beta或过去的回报用作您的x变量):

In [1]: import pandas as pd
        import numpy as np
        import statsmodels.formula.api as smf

In [4]: df = pd.read_csv('industry.csv',parse_dates=['caldt'])
        df.query("caldt == '1995-07-01'")

In [5]: Out[5]: 
      industry      caldt    ret    beta  r12to2  r36to13
18432     Aero 1995-07-01   6.26  0.9696  0.2755   0.3466
18433    Agric 1995-07-01   3.37  1.0412  0.1260   0.0581
18434    Autos 1995-07-01   2.42  1.0274  0.0293   0.2902
18435    Banks 1995-07-01   4.82  1.4985  0.1659   0.2951
Run Code Online (Sandbox Code Playgroud)

Fama-MacBeth主要涉及逐月计算相同的横截面回归模型,因此您可以使用a来实现它groupby.你可以创建一个函数,它接受dataframe(它将来自groupby)和一个patsy公式; 然后它适合模型并返回参数估计值.这里是你如何能够实现它(注意这是一个准系统版本是什么原来的提问试着做了几年前......不知道为什么它没有工作,虽然它可能当时statsmodels导致对象的方法params没有一个返回pandas Series所以返回需要转换为Series显式...它在当前版本的pandas0.23.4 中工作正常:

def ols_coef(x,formula):
    return smf.ols(formula,data=x).fit().params

In [9]: gamma = (df.groupby('caldt')
                .apply(ols_coef,'ret ~ 1 + beta + r12to2 + r36to13'))
        gamma.head()

In [10]: Out[10]: 
            Intercept      beta     r12to2   r36to13
caldt                                               
1963-07-01  -1.497012 -0.765721   4.379128 -1.918083
1963-08-01  11.144169 -6.506291   5.961584 -2.598048
1963-09-01  -2.330966 -0.741550  10.508617 -4.377293
1963-10-01   0.441941  1.127567   5.478114 -2.057173
1963-11-01   3.380485 -4.792643   3.660940 -1.210426
Run Code Online (Sandbox Code Playgroud)

然后计算平均值,平均值的标准误差和t检验(或任何你想要的统计数据).类似于以下内容:

def fm_summary(p):
    s = p.describe().T
    s['std_error'] = s['std']/np.sqrt(s['count'])
    s['tstat'] = s['mean']/s['std_error']
    return s[['mean','std_error','tstat']]

In [12]: fm_summary(gamma)
Out[12]: 
               mean  std_error     tstat
Intercept  0.754904   0.177291  4.258000
beta      -0.012176   0.202629 -0.060092
r12to2     1.794548   0.356069  5.039896
r36to13    0.237873   0.186680  1.274230
Run Code Online (Sandbox Code Playgroud)

提高速度

使用statsmodels的回归有显著的开销(特别是考虑到你只需要估计系数).如果你想要更高的效率,那么你可以切换statsmodelsnumpy.linalg.lstsq.编写一个执行ols估计的新函数......类似于以下内容(注意我没有做任何事情,比如检查这些矩阵的等级......):

def ols_np(data,yvar,xvar):
    gamma,_,_,_ = np.linalg.lstsq(data[xvar],data[yvar],rcond=None)
    return pd.Series(gamma)
Run Code Online (Sandbox Code Playgroud)

如果您仍在使用旧版本pandas,则以下内容将起作用:

以下是使用该fama_macbeth函数的示例pandas:

>>> df

                y    x
date       id
2012-01-01 1   0.1  0.4
           2   0.3  0.6
           3   0.4  0.2
           4   0.0  1.2
2012-02-01 1   0.2  0.7
           2   0.4  0.5
           3   0.2  0.1
           4   0.1  0.0
2012-03-01 1   0.4  0.8
           2   0.6  0.1
           3   0.7  0.6
           4   0.4 -0.1
Run Code Online (Sandbox Code Playgroud)

注意,结构.该fama_macbeth函数期望y-var和x-vars具有多索引,其中date作为第一个变量,stock/firm/entity id作为索引中的第二个变量:

>>> fm  = pd.fama_macbeth(y=df['y'],x=df[['x']])
>>> fm


----------------------Summary of Fama-MacBeth Analysis-------------------------

Formula: Y ~ x + intercept
# betas :   3

----------------------Summary of Estimated Coefficients------------------------
     Variable          Beta       Std Err        t-stat       CI 2.5%      CI 97.5%
          (x)       -0.0227        0.1276         -0.18       -0.2728        0.2273
  (intercept)        0.3531        0.0842          4.19        0.1881        0.5181

--------------------------------End of Summary---------------------------------
Run Code Online (Sandbox Code Playgroud)

请注意,只需打印fm调用fm.summary

>>> fm.summary

----------------------Summary of Fama-MacBeth Analysis-------------------------

Formula: Y ~ x + intercept
# betas :   3

----------------------Summary of Estimated Coefficients------------------------
     Variable          Beta       Std Err        t-stat       CI 2.5%      CI 97.5%
          (x)       -0.0227        0.1276         -0.18       -0.2728        0.2273
  (intercept)        0.3531        0.0842          4.19        0.1881        0.5181

--------------------------------End of Summary---------------------------------
Run Code Online (Sandbox Code Playgroud)

另外,请注意该fama_macbeth函数会自动添加一个截距(与statsmodels例程相对).x-var也必须dataframe如此,如果只传递一列,则需要传递它df[['x']].

如果你不想要拦截,你必须这样做:

>>> fm  = pd.fama_macbeth(y=df['y'],x=df[['x']],intercept=False)
Run Code Online (Sandbox Code Playgroud)