<p>反映Fama MacBeth截至2018年秋季图书馆情况的更新。<code>fama_macbeth</code>函数已从<code>pandas</code>中删除一段时间。你有什么选择?</p>
<ol>
<li><p>如果您使用的是python 3,那么可以在LinearModels中使用Fama MacBeth方法:<a href="https://github.com/bashtage/linearmodels/blob/master/linearmodels/panel/model.py" rel="nofollow noreferrer">https://github.com/bashtage/linearmodels/blob/master/linearmodels/panel/model.py</a></p></li>
<li><p>如果您使用的是Python2,或者只是不想使用LinearModels,那么您最好的选择可能是滚动您自己的。</p></li>
</ol>
<p>例如,假设您将Fama-French行业投资组合放在一个面板中,如下所示(您还计算了一些变量,如过去的beta或过去的回报率,用作x变量):</p>
<pre><code>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
</code></pre>
<p>Fama-MacBeth主要涉及逐月计算相同的横截面回归模型,因此可以使用<code>groupby</code>实现它。您可以创建一个函数,该函数接受一个<code>dataframe</code>(它将来自<code>groupby</code>)和一个<code>patsy</code>公式;然后它适合模型并返回参数估计值。这是一个你如何实现它的简单版本(注意这是最初的提问者几年前试图做的。。。不知道为什么它不起作用,尽管在当时可能<code>statsmodels</code>结果对象方法<code>params</code>没有返回<code>pandas</code><code>Series</code>,所以需要显式地将返回转换为<code>Series</code>。。。它在当前版本的<code>pandas</code>,0.23.4)中工作正常:</p>
<pre><code>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
</code></pre>
<p>然后计算平均值,平均值的标准误差,然后进行t检验(或者任何你想要的统计数据)。大致如下:</p>
<pre><code>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
</code></pre>
<p><strong>提高速度</strong></p>
<p>使用<code>statsmodels</code>进行回归有很大的开销(特别是考虑到您只需要估计的系数)。如果你想要更好的效率,那么你可以从<code>statsmodels</code>切换到<code>numpy.linalg.lstsq</code>。写一个新的函数来做ols估计。。。如下所示(注意,我没有检查这些矩阵的秩…)</p>
<pre><code>def ols_np(data,yvar,xvar):
gamma,_,_,_ = np.linalg.lstsq(data[xvar],data[yvar],rcond=None)
return pd.Series(gamma)
</code></pre>
<p>如果您仍然使用较旧版本的<code>pandas</code>,则以下操作将起作用:</p>
<p>下面是在<code>pandas</code>中使用<code>fama_macbeth</code>函数的示例:</p>
<pre><code>>>> 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
</code></pre>
<p>注意,结构。函数<code>fama_macbeth</code>期望y-var和x-vars在索引中有一个日期为第一变量、股票/公司/实体id为第二变量的多个索引:</p>
<pre><code>>>> 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---------------------------------
</code></pre>
<p>注意,只打印<code>fm</code>调用fm.summary</p>
<pre><code>>>> 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---------------------------------
</code></pre>
<p>另外,注意<code>fama_macbeth</code>函数会自动添加一个截距(与<code>statsmodels</code>例程相反)。而且x-var必须是<code>dataframe</code>,因此如果只传递一列,则需要将其作为<code>df[['x']]</code>传递。</p>
<p>如果你不想拦截,你必须:</p>
<pre><code>>>> fm = pd.fama_macbeth(y=df['y'],x=df[['x']],intercept=False)
</code></pre>