You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Pandas中使用ffill填充多事件值时的代码覆盖问题

问题描述

我有一个可简化为如下形式的DataFrame:

import numpy as np
import pandas as pd

TR = [17,18,19,20,21,22,23,24,25,26,27,28,29]
Event = ['SRNeg', np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, 'Rating', np.NaN, np.NaN, 'ArrowTask', np.NaN]
df = pd.DataFrame({'Event':Event,'TR':TR})

需要将事件值后的部分NaN填充为该事件值(并非所有NaN都需填充),理想输出如下:

TR = [17,18,19,20,21,22,23,24,25,26,27,28,29]
Event = ['SRNeg', np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, 'Rating', np.NaN, np.NaN, 'ArrowTask', np.NaN]
Event_BOLD_Duration = ['SRNeg', 'SRNeg', 'SRNeg', 'SRNeg', 'SRNeg', 'SRNeg', 'SRNeg', 'SRNeg', 'Rating', 'Rating', np.NaN, 'ArrowTask', 'ArrowTask']
df = pd.DataFrame({'Event':Event,'Event_BOLD_Duration':Event_BOLD_Duration,'TR':TR})

我原本编写了如下代码,但每行代码都会覆盖前一行的输出结果:

# line 1
scores_full['Event_BOLD_Duration'] = scores_full['Event'].where(scores_full['Event'].isin(['SRNeg', 'SINeg'])).ffill(limit=7).fillna(scores_full['Event']) 
# line 2
scores_full['Event_BOLD_Duration'] = scores_full['Event'].where(scores_full['Event'].isin(['ArrowTask'])).ffill(limit=4).fillna(scores_full['Event']) 
# line 3
scores_full['Event_BOLD_Duration'] = scores_full['Event'].where(scores_full['Event'].isin(['Rating'])).ffill(limit=1).fillna(scores_full['Event'])
解决方案

你的问题出在每次赋值都直接从原始Event列重新生成数据,完全覆盖了之前的处理结果。正确的做法是先初始化目标列,再针对不同事件类型逐个填充后续指定数量的NaN。

实现代码

import numpy as np
import pandas as pd

# 初始化DataFrame
TR = [17,18,19,20,21,22,23,24,25,26,27,28,29]
Event = ['SRNeg', np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, 'Rating', np.NaN, np.NaN, 'ArrowTask', np.NaN]
df = pd.DataFrame({'Event':Event,'TR':TR})

# 初始化目标列,先复制原始Event值
df['Event_BOLD_Duration'] = df['Event'].copy()

# 1. 处理SRNeg/SINeg:每个事件后填充7行
for event in ['SRNeg', 'SINeg']:
    # 获取所有该事件的索引
    event_idx_list = df[df['Event'] == event].index
    for idx in event_idx_list:
        # 计算填充的结束位置,避免超出DataFrame范围
        fill_end = min(idx + 7, df.index[-1])
        # 填充从idx+1到fill_end的行
        df.loc[idx+1:fill_end, 'Event_BOLD_Duration'] = event

# 2. 处理Rating:每个事件后填充1行
event_idx_list = df[df['Event'] == 'Rating'].index
for idx in event_idx_list:
    fill_end = min(idx + 1, df.index[-1])
    if fill_end > idx:  # 确保存在可填充的行
        df.loc[idx+1:fill_end, 'Event_BOLD_Duration'] = 'Rating'

# 3. 处理ArrowTask:每个事件后填充1行(匹配你的理想输出)
event_idx_list = df[df['Event'] == 'ArrowTask'].index
for idx in event_idx_list:
    fill_end = min(idx + 1, df.index[-1])
    if fill_end > idx:
        df.loc[idx+1:fill_end, 'Event_BOLD_Duration'] = 'ArrowTask'

代码说明

  • 先复制原始Event列到Event_BOLD_Duration,保留所有原始非NaN值
  • 针对每个事件类型,找到其出现的索引,然后向后填充指定数量的行
  • 使用min(idx + N, df.index[-1])避免超出DataFrame的最后一行索引,防止报错

执行后即可得到你想要的理想输出。

内容的提问来源于stack exchange,提问作者jo_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:20:43