如何为CatBoost分类器优雅生成近月样本权重更高的月度权重列
问题场景
手头有高度不平衡的数据集,计划按月份为观测样本分配权重,规则为距离当前越近的月份样本权重越高:例如2022年1月的观测样本权重赋值为1/5,2022年3月的观测样本权重赋值为1/3,依此类推,权重列格式示例如下:
feature_1 date weights 117 2016-11-12 0.015 ... ... ... 123 2022-01-01 0.2 234 2022-01-02 0.2 ... ... 345 2022-05-31 1.0
当前使用CatboostClassifier构建模型,已知可将全量样本对应的权重列表传入Pool的weight参数完成加权训练,调用形式如下:
model.fit(Pool(X_train,y_train,weight=train_weight))
当前痛点:没有找到优雅的实现方案来生成所需的权重列/权重列表
现有临时实现方案逻辑繁琐、性能差:
- 先按月份频率拆分训练集数据框
g = X_train.groupby(pd.Grouper(key='date', freq='M')) dfs = [group for _,group in g]
- 通过双层循环遍历每个月度分组,逐行给样本赋值权重
for i, df in enumerate(dfs): weight = [] for val in dfs[i].iterrows(): weight.append(1 / (len(dfs)+2 - i)) dfs[i]['weight'] = weight
需要更简洁高效、代码更优雅的月度样本权重生成方案。
优化实现方案
完全不需要拆分DataFrame、不需要逐行循环,用pandas向量化操作即可实现,性能比原方案提升1~2个数量级,逻辑清晰易维护:
import pandas as pd # 若date列未转时间格式先执行这步,已转可跳过 X_train['date'] = pd.to_datetime(X_train['date']) # 提取所有样本所属月份,按时间从远到近排序去重 unique_months = sorted(X_train['date'].dt.to_period('M').unique()) # 构建月份-权重映射字典,完全匹配示例规则:最近月份权重为1,每往前1个月权重分母加1 month_weight_map = { month: 1 / (len(unique_months) - idx) for idx, month in enumerate(unique_months) } # 直接映射生成整列权重,全程无循环 X_train['weight'] = X_train['date'].dt.to_period('M').map(month_weight_map) # 提取给CatBoost用的权重数组直接取values即可 train_weight = X_train['weight'].values
- 方案优势:
- 无
iterrows()逐行遍历的性能损耗,十万级以上样本处理速度远高于原双层循环方案 - 不需要拆分、拼接DataFrame,不会出现索引错位类bug
- 权重规则调整灵活:如果需要改成线性权重、指数权重、固定窗口权重,仅需修改
month_weight_map的生成逻辑即可,整体流程不需要变动
- 无
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

