Python实现按季度与公司ID的列子集线性回归
按季度和公司ID分组线性回归并合并结果到原数据集
问题描述
我有一份日度股票收益数据集,需要按季度(qtr)和公司ID(PERMNO)将个股收益(FIRMRF)对市场收益(MKTRF)做线性回归,把每家公司每季度回归得到的斜率(beta)和标准误差存入原DataFrame,同一季度的回归值要在该季度的每一行重复显示。
数据集结构示例:
date PERMNO MCAP FIRMRF MKTRF qtr 0 2018-01-02 10026 2.784892e+06 -0.017514 0.0085 1 7339 2018-01-03 10026 2.757077e+06 -0.010048 0.0059 1 14671 2018-01-04 10026 2.795160e+06 0.013753 0.0042 1 22003 2018-01-05 10026 2.768464e+06 -0.009610 0.0066 1 29334 2018-01-08 10026 2.770518e+06 0.000682 0.0019 1 ... ... ... ... ... ... ... 8455011 2022-03-25 93436 1.044531e+09 -0.003235 0.0027 1 8464495 2022-03-28 93436 1.128454e+09 0.080345 0.0073 1 8473980 2022-03-29 93436 1.136443e+09 0.007080 0.0145 1 8483469 2022-03-30 93436 1.130676e+09 -0.005075 -0.0083 1 8492959 2022-03-31 93436 1.113736e+09 -0.014982 -0.0155 1
我当前的代码框架:
for i in daily['qtr']: for x in daily['PERMNO']: reg = sm.OLS(daily['FIRMRF'], sm.add_constant(daily['MKTRF'])) results = reg.fit()
但这段代码没有实现分组回归的效果,尝试修改多个方案均失败,需要帮助。
解决方案
问题分析
当前代码的核心问题是没有按PERMNO和qtr分组处理,每次循环都用整个数据集做回归,并且错误地遍历了单个qtr和PERMNO值,而非对分组后的子数据集执行回归。
正确实现步骤
- 用
pandas的groupby按PERMNO和qtr分组,对每个子数据集执行回归。 - 为每个分组提取
MKTRF对应的系数(beta)和标准误差,生成包含分组键、beta、beta标准误差的新DataFrame。 - 将新DataFrame与原数据集按
PERMNO和qtr合并,实现同一分组的所有行填充对应回归结果。
代码实现
import pandas as pd import statsmodels.api as sm # 定义回归函数,输入分组子数据集,返回beta及标准误差 def run_regression(group): # 处理样本量不足的情况,避免报错 if len(group) < 2: return pd.Series({'beta': None, 'beta_std_err': None}) X = sm.add_constant(group['MKTRF']) # 添加截距项 y = group['FIRMRF'] model = sm.OLS(y, X).fit() return pd.Series({ 'beta': model.params['MKTRF'], 'beta_std_err': model.bse['MKTRF'] }) # 按公司和季度分组执行回归 reg_results = daily.groupby(['PERMNO', 'qtr']).apply(run_regression).reset_index() # 合并回归结果到原数据集 daily_with_results = pd.merge(daily, reg_results, on=['PERMNO', 'qtr'], how='left')
关键说明
groupby(['PERMNO', 'qtr']):确保每个分组是单家公司单个季度的所有日度数据,避免跨公司或跨季度的错误回归。apply(run_regression):自动对每个分组执行回归,返回的Series会与分组键组合成结构化的结果DataFrame。pd.merge:通过双主键合并,保证原数据集中同一公司同一季度的所有行都能匹配到对应的beta值和标准误差。
额外提示
如果当前qtr仅为1-4的数字,建议结合年份生成复合季度标识(比如daily['year_qtr'] = daily['date'].dt.year * 10 + daily['qtr']),避免不同年份的同季度被错误归为一组。
内容的提问来源于stack exchange,提问作者AustinSobotka
相关产品推荐
相关产品推荐

