金融资产定价常常需要用到FamaMacBeth回归。我们用python写一个模板,可以直接将数据调成需要的格式,代入代码即可出结果。所要求的数据格式,可以从链接下载。

需要注意的是,linearmodels中的FamaMacBeth( )方法一共执行了两步:第一步,在每个时间t的横截面上,用Y对X回归,然后产生一条由各个时间上的X的回归系数组成的时间序列;第二步,对X的回归系数的时间序列进行统计检验,分别计算他们的均值、t值、P值等。

首先载入代码框架

from linearmodels import FamaMacBeth
import pandas as pd
import numpy as np

class MyFamaMacBeth():

    def __init__(self,
                 ):
        pass

    #根据P值返回星号
    def star(self,p):
        if p<0.01:
            return '***'
        elif p<=0.05:
            return '**'
        elif p<=0.1:
            return '*'
        else:
            return ''

    #基本FM回归:一次只能回归一种模型
    def basic_FM(self,
        data,#面板数据
        Cols_X=['const','X1','X2','X3','X4','X5','X6','X7','X8'],#解释变量列标题
        Col_Y='Y',#被解释变量列标题
        Col_date='date',#日期的列标题
        Col_individual='individual',#个体的列标题
                 ):
        self.Cols_X=Cols_X
        self.Col_Y=Col_Y

        # 将数据格式修改为多个行标签的面板数据
        data = pd.pivot_table(data, index=[Col_date,Col_individual],
                              values=[Col_Y]+Cols_X)

        # 回归模型
        model = FamaMacBeth(dependent=data[Col_Y], exog=data[Cols_X])
        # 回归结果用Newey West方法进行调整,滞后阶数设置为6阶
        result = model.fit(cov_type='kernel', debiased=False, bandwidth=6)

        return result

    def basic_FM_summary(self,result,col_result='model',path_save=False):

        params=result.params
        t=result.tstats
        p=result.pvalues
        star=[self.star(x) for x in p]
        #数据合并
        values=pd.DataFrame({
            'Varible':params.index,
            'params':params,
            't':t,
            'star':star
        })
        #保留小数位数
        values['params']=values['params'].round(3).astype(str)
        values['t'] = values['t'].round(2).astype(str)
        #数据合并
        summary=pd.DataFrame({
            col_result:values['params']+values['star']+'('+values['t']+')',
        })
        summary=summary.append(pd.DataFrame([round(result.rsquared,3),len(result.resids)],index=[' Adj. R',' No. of obs'],columns=[col_result]))

        if path_save:
            summary.to_excel(path_save)

        return summary



    #FM回归,含有不同的模型
    def FM_multiple_models(self,
                           data,
                           models=[],
                           Col_date='date',  # 日期的列标题
                           Col_individual='individual',  # 个体的列标题
                           ):
        all_results={}
        all_summarys=[]
        for model in models:
            result = MFMB.basic_FM(data,  # 面板数据
                                             Cols_X=models[model]['X'],
                                             # 解释变量列标题
                                             Col_Y=models[model]['Y'],  # 被解释变量列标题
                                             Col_date=Col_date,  # 日期的列标题
                                             Col_individual=Col_individual,  # 个体的列标题
                                             )
            all_results[model]=result

            summary = MFMB.basic_FM_summary(result, col_result=model)
            all_summarys.append(summary)

        return all_results,all_summarys

    # 为 "FM回归,含有不同的模型" 整理出简洁结果
    def FM_multiple_models_summary(self,all_summarys,path_save=False):
        all_summarys=pd.concat(all_summarys,axis=1)
        all_summarys.sort_index(inplace=True)

        #保存路径
        if path_save:
            all_summarys.to_excel(path_save)

        return all_summarys

第一种使用方式,针对一种模型进行Fama回归:

###使用方式1:基本FM回归,一次只能回归一种模型
    ######################################
    # 第一步,生成测试所用面板数据集,该数据集在不同的日期有不同的个体
    # 期望回归模型:Y=3.4+6.6*X1-4*X2+7*X3-3*X4-4.9*X5+7.4*X6-4*X7-7.1*X8
    data = [[date, i] for date in pd.date_range('20050102', end='20060908', freq='D') for i in
            range(np.random.randint(20, 87))]  # 生成日期和个体
    data = pd.DataFrame(data, columns=['date', 'individual'])
    data['const'] = 1  # 生成常数项
    data[['X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']] = pd.DataFrame(np.random.normal(size=[len(data), 8]))  # 解释变量
    data['Y'] = 3.4 * data['const'] + 6.6 * data['X1'] - 4 * data['X2'] + 7 * data['X3'] - 3 * data['X4'] - 4.9 * data[
        'X5'] + 7.4 * data['X6'] - 4 * data['X7'] - 7.1 * data['X8'] + np.random.normal(size=len(data)) / 10  # 被解释变量

    #第二步,回归
    MFMB=MyFamaMacBeth()
    result=MFMB.basic_FM(data,#面板数据
        Cols_X=['const','X1','X2','X3','X4','X5','X6','X7','X8'],#解释变量列标题
        Col_Y='Y',#被解释变量列标题
        Col_date='date',#日期的列标题
        Col_individual='individual',#个体的列标题
        )

    # 第三步,整理出简洁结果
    summary=MFMB.basic_FM_summary(result, col_result='model',path_save='单Fama面板回归结果.xlsx')

第二种用法,可以同时针对多种模型进行回归:

###使用方式2:FM回归,含有不同的模型
    ######################################
    # 第一步,生成测试所用面板数据集,该数据集在不同的日期有不同的个体
    data = [[date, i] for date in pd.date_range('20050102', end='20060908', freq='D') for i in
            range(np.random.randint(20, 87))]  # 生成日期和个体
    data = pd.DataFrame(data, columns=['date', 'individual'])
    data['const'] = 1  # 生成常数项
    data[['X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']] = pd.DataFrame(np.random.normal(size=[len(data), 8]))  # 解释变量
    # 期望回归模型:Y1=3.4+6.6*X1-4*X2+7*X3-3*X4-4.9*X5+7.4*X6-4*X7-7.1*X8
    data['Y1'] = 3.4 * data['const'] + 6.6 * data['X1'] - 4 * data['X2'] + 7 * data['X3'] - 3 * data['X4'] - 4.9 * data[
        'X5'] + 7.4 * data['X6'] - 4 * data['X7'] - 7.1 * data['X8'] + np.random.normal(size=len(data)) / 10  # 被解释变量
    # 期望回归模型:Y2=-7.9-2*X1-1.9*X2+7.4*X3+3.5*X4+9.4*X5-5.2*X6-4.8*X7
    data['Y2'] = -7.9 * data['const'] -2 * data['X1'] - 1.9 * data['X2'] + 7.4 * data['X3'] + 3.5 * data['X4'] +9.4 * data[
        'X5'] -5.2 * data['X6'] - 4.8 * data['X7']  + np.random.normal(size=len(data)) / 10  # 被解释变量
    # 期望回归模型:Y3=8.4+2.1*X1+2.9*X2-2.8*X3-9.3*X4+7.7*X5
    data['Y3'] = 8.4 * data['const'] + 2.1 * data['X1'] +2.9 * data['X2'] - 2.8 * data['X3'] - 9.3 * data['X4'] +7.7 * data[
        'X5'] + np.random.normal(size=len(data)) / 10  # 被解释变量



    # 第二步,回归
    MFMB = MyFamaMacBeth()
    all_results,all_summarys = MFMB.FM_multiple_models(data,  # 面板数据
                                    #将模型结构按照顺序填进来
                                     models={
                                         'model1':{'Y':'Y1','X':['const','X1', 'X2','X7', 'X8']},
                                         'model2':{'Y':'Y1','X':['const','X1', 'X2',  'X5',  'X7', 'X8']},
                                         'model3':{'Y':'Y1','X':['const','X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']},
                                         'model4':{'Y':'Y2','X':['const','X1', 'X2', 'X3', 'X4', 'X5']},
                                         'model5': {'Y': 'Y2',
                                                    'X': ['const', 'X1', 'X2', 'X3',  'X6', 'X7']},
                                         'model6': {'Y': 'Y3',
                                                    'X': ['const', 'X1', 'X2', 'X3', 'X4', 'X5']},
                                     },
                                     Col_date='date',  # 日期的列标题
                                     Col_individual='individual',  # 个体的列标题
                                     )

    # 第三步,整理出简洁结果
    all_summarys=MFMB.FM_multiple_models_summary(all_summarys=all_summarys,path_save='Fama面板回归结果.xlsx')