如何在Pandas DataFrame中按月基于B/M指标生成指定规则的新列?
Pandas 分组打标实现方案
核心思路为按日期分组后对B/M指标做二分位切割,无需拆分出多个单月DataFrame,即可完成Signal列批量赋值。
方法1:qcut 快速实现(推荐标准场景使用)
import pandas as pd # 按日期(索引)分组,将每组B/M等分为2组,直接对应标签-1和1 df['Signal'] = df.groupby(level='Date')['B/M'].transform( lambda x: pd.qcut(x, q=2, labels=[-1, 1]) ) # 按需转换为整数类型 df['Signal'] = df['Signal'].astype(int)
逻辑说明:
groupby(level='Date'):按索引列Date分组,单月所有股票为一组;如果你的Date后续调整为普通列,替换为groupby('Date')即可pd.qcut(x, q=2):将每组B/M值按数量等分为2份,前50%(低B/M)对应标签-1,后50%(高B/M)对应标签1,和你给出的预期输出完全匹配- 如果单月样本量为奇数,qcut默认将多出来的1条样本分到高B/M组,符合常规金融因子分组的惯例。如果需要处理重复的B/M值,可以增加
duplicates='drop'参数适配。
方法2:rank 自定义实现(适合需要调整重复值规则的场景)
如果需要自定义相同B/M值的分组逻辑,可以用排名+阈值判断的方式实现:
# 分组计算单月B/M排名、单月样本总量 df['bm_rank'] = df.groupby(level='Date')['B/M'].rank(method='first') df['month_sample_cnt'] = df.groupby(level='Date')['B/M'].transform('count') # 按排名是否超过中位数判断Signal值 df['Signal'] = df.apply(lambda x: 1 if x['bm_rank'] > x['month_sample_cnt']/2 else -1, axis=1) # 删除辅助列 df = df.drop(columns=['bm_rank', 'month_sample_cnt'])
可以通过调整rank的method参数修改重复值的排名规则:可选值包括average/min/max/first/dense,适配不同的业务需求。
内容的提问来源于stack exchange,提问作者Gonçalo Franchini
相关产品推荐
相关产品推荐

