基于前一行填充Pandas列的特殊需求实现
嘿,这个Pandas的连续序列填充问题我之前也碰到过,确实有点绕,不过用分组+标志位的思路就能搞定。先给你理清楚核心逻辑:
- 先把
status为EXPIRED的行直接过滤掉,这些行不参与计算 - 按
symbol分组,在每个组里识别新的BUY序列起始点——也就是当前行是BUY,且上一行不是BUY(或者是组内第一行) - 给每个连续BUY序列分配唯一的ID,然后在每个序列内从0开始递增计数
- 非BUY的行(比如SELL)可以设置为
None或者你需要的默认值
方案一:易理解的分步写法(适合小数据集)
这种写法逻辑直白,新手也能轻松看懂每一步的作用:
# 第一步:过滤掉EXPIRED的行,一定要用copy避免SettingWithCopyWarning df = df[df['status'] != 'EXPIRED'].copy() # 定义分组处理函数 def process_symbol_group(group): # 标记新BUY序列的起始点 group['is_new_buy_seq'] = False # 组内第一行如果是BUY,就是新序列的开始 if group.iloc[0]['order_type'] == 'BUY': group.iloc[0, group.columns.get_loc('is_new_buy_seq')] = True # 遍历后续行,判断是否开启新BUY序列 for idx in range(1, len(group)): prev_order = group.iloc[idx-1]['order_type'] curr_order = group.iloc[idx]['order_type'] # 上一行不是BUY,当前是BUY → 新序列开始 if prev_order != 'BUY' and curr_order == 'BUY': group.iloc[idx, group.columns.get_loc('is_new_buy_seq')] = True # 用cumsum生成每个BUY序列的唯一ID group['seq_id'] = group['is_new_buy_seq'].cumsum() # 对每个BUY序列计算递增计数,非BUY行设为None group['final_column'] = group.apply( lambda row: row.groupby('seq_id').cumcount() if row['order_type'] == 'BUY' else None, axis=1 ) # 清理中间临时列(可选) group.drop(['is_new_buy_seq', 'seq_id'], axis=1, inplace=True) return group # 应用到每个symbol分组 df = df.groupby('symbol').apply(process_symbol_group).reset_index(drop=True)
方案二:高效向量式写法(适合大数据集)
如果你的数据集很大,循环会拖慢速度,用Pandas的向量操作能大幅提升效率:
# 第一步:过滤无效行 df = df[df['status'] != 'EXPIRED'].copy() # 按symbol分组,获取上一行的order_type df['prev_order_type'] = df.groupby('symbol')['order_type'].shift(1) # 标记新BUY序列的起始点:当前是BUY,且上一行不是BUY(或为组内第一行) df['is_new_buy_seq'] = (df['order_type'] == 'BUY') & ( (df['prev_order_type'] != 'BUY') | df['prev_order_type'].isna() ) # 生成每个symbol内的序列ID df['seq_id'] = df.groupby('symbol')['is_new_buy_seq'].cumsum() # 计算最终列:BUY序列内从0开始递增,非BUY行设为None df['final_column'] = df.groupby(['symbol', 'seq_id'])['order_type'].transform( lambda x: x.cumcount() if x.iloc[0] == 'BUY' else None ) # 清理临时列 df.drop(['prev_order_type', 'is_new_buy_seq', 'seq_id'], axis=1, inplace=True)
补充说明
- 如果非BUY行(比如SELL)需要设置特定值(比如空字符串、0),直接修改最后一步的
None为你需要的值即可 - 测试的时候可以先拿一小部分数据跑,确认逻辑符合预期再应用到全量数据
内容的提问来源于stack exchange,提问作者nidkil
相关产品推荐
相关产品推荐

