如何基于sec_ID检测code列首次变更?附DataFrame处理需求
解决按证券分组检测code首次变更的问题
你的核心问题是没有按sec_ID分组独立计算code的变化:原始代码里的data['code'].diff()是全局计算差异,会跨不同证券的行进行比对,导致错误识别跨组的"变更"。针对你400万行的大数据量,我提供两种高效的解决方案,都能保证每个证券的检测逻辑独立重置:
方案一:分组自定义逻辑(直观易读)
通过groupby.apply()对每个证券组单独处理逻辑,适合需要清晰理解每一步的场景:
import pandas as pd # 确保数据已按sec_ID和date升序排序(你提到已完成此步骤) def process_sec_group(group): # 获取当前证券的初始code值(首行的code) initial_code = group['code'].iloc[0] # 情况1:该证券所有code始终为初始值(0),返回首行 if (group['code'] == initial_code).all(): return group.iloc[[0]] # 情况2:存在code变更,返回第一个变更的行 else: # 找到第一个不等于初始值的行的索引 first_change_pos = group[group['code'] != initial_code].index[0] return group.loc[[first_change_pos]] # 应用逻辑到每个分组,合并结果 final_result = data.groupby('sec_ID', group_keys=False).apply(process_sec_group).reset_index(drop=True)
方案二:矢量化分组diff(性能更优)
针对大数据量,优先用矢量化操作替代apply,速度更快:
# 1. 按sec_ID分组,计算组内code的差异(每个组独立计算diff,跨组不会干扰) data['group_code_diff'] = data.groupby('sec_ID')['code'].diff() # 2. 标记每个证券是否存在code变更 has_code_change = data.groupby('sec_ID')['group_code_diff'].any() # 3. 提取两类目标行: # - 有变更的证券:取第一个diff非0的行 first_change_rows = data[ data['group_code_diff'].notna() & (data['group_code_diff'] != 0) ].groupby('sec_ID').nth(0) # - 无变更的证券:取首行 no_change_rows = data[ data['sec_ID'].isin(has_code_change[~has_code_change].index) ].groupby('sec_ID').nth(0) # 4. 合并结果并整理格式 final_result = pd.concat([first_change_rows, no_change_rows]).reset_index() final_result = final_result.sort_values('sec_ID').reset_index(drop=True)
结果验证
用你提供的示例数据测试,两种方案都会得到期望的输出:
| date | sec_ID | code |
|---|---|---|
| 2015-12-18 | abc | 1 |
| 2016-01-16 | def | 0 |
| 2016-11-17 | xyz | -1 |
内容的提问来源于stack exchange,提问作者SQLGIT_GeekInTraining
相关产品推荐
相关产品推荐

