Pandas条件填充失效:按规则填充infected字段的技术问题
问题:按规则填充DataFrame的infected字段
以下是我的DataFrame创建及填充代码:
import pandas as pd import numpy as np sample_data = [ {'Date': '13-12-2020', 'usable': 1, 'infected': 'Case3'}, {'Date': '14-12-2020', 'usable': 1}, {'Date': '15-12-2020', 'usable': 0}, {'Date': '16-12-2020', 'usable': 1, 'infected': 'Case33'}, {'Date': '17-12-2020', 'usable': 1}, {'Date': '18-12-2020', 'usable': 1}, {'Date': '19-12-2020', 'usable': 0}, {'Date': '20-12-2020', 'usable': 0}, {'Date': '21-12-2020', 'usable': 0, 'infected': 'Case#'}, {'Date': '22-12-2020', 'usable': 1}, {'Date': '23-12-2020', 'usable': 1}, {'Date': '24-12-2020', 'usable': 0}, {'Date': '25-12-2020', 'usable': 0}, {'Date': '26-12-2020', 'usable': 1, 'infected': 'Case46'}, {'Date': '27-12-2020', 'usable': 0}, {'Date': '28-12-2020', 'usable': 1}, ] df = pd.DataFrame(sample_data) df['infected'] = df['infected'].ffill(limit=2).bfill(limit=2) df['infected'] = np.where(df['usable']==0, np.NaN, df['infected'])
我需要按以下规则填充infected字段:
- 仅对
usable=1的行填充infected值 - 向前后最多填充2个相邻的
usable=1的行 - 遇到
usable=0时停止填充
但当前代码得到错误输出,预期输出如下:
expected = [ {'Date': '13-12-2020', 'usable': 1, 'infected': 'Case3'}, {'Date': '14-12-2020', 'usable': 1, 'infected': 'Case3'}, {'Date': '15-12-2020', 'usable': 0}, {'Date': '16-12-2020', 'usable': 1, 'infected': 'Case33'}, {'Date': '17-12-2020', 'usable': 1, 'infected': 'Case33'}, {'Date': '18-12-2020', 'usable': 1, 'infected': 'Case33'}, {'Date': '19-12-2020', 'usable': 0}, {'Date': '20-12-2020', 'usable': 0}, {'Date': '21-12-2020', 'usable': 0, 'infected': 'Case#'}, {'Date': '22-12-2020', 'usable': 1}, {'Date': '23-12-2020', 'usable': 1}, {'Date': '24-12-2020', 'usable': 0}, {'Date': '25-12-2020', 'usable': 0}, {'Date': '26-12-2020', 'usable': 1, 'infected': 'Case46'}, {'Date': '27-12-2020', 'usable': 0}, {'Date': '28-12-2020', 'usable': 1}, ] df_expected = pd.DataFrame(expected)
注:'28-12-2020'不填充'Case46',因为'27-12-2020'的usable=0,无法向前填充。
解决方案
原代码的问题在于直接使用ffill和bfill会忽略usable=0的分隔作用,导致跨usable=0的行填充,同时无法精确控制仅在连续usable=1的块内填充最多2个相邻行。
正确的做法是先按usable=0分割出连续的usable=1的组,再在每个组内进行前后填充,限制填充次数为2:
import pandas as pd import numpy as np sample_data = [ {'Date': '13-12-2020', 'usable': 1, 'infected': 'Case3'}, {'Date': '14-12-2020', 'usable': 1}, {'Date': '15-12-2020', 'usable': 0}, {'Date': '16-12-2020', 'usable': 1, 'infected': 'Case33'}, {'Date': '17-12-2020', 'usable': 1}, {'Date': '18-12-2020', 'usable': 1}, {'Date': '19-12-2020', 'usable': 0}, {'Date': '20-12-2020', 'usable': 0}, {'Date': '21-12-2020', 'usable': 0, 'infected': 'Case#'}, {'Date': '22-12-2020', 'usable': 1}, {'Date': '23-12-2020', 'usable': 1}, {'Date': '24-12-2020', 'usable': 0}, {'Date': '25-12-2020', 'usable': 0}, {'Date': '26-12-2020', 'usable': 1, 'infected': 'Case46'}, {'Date': '27-12-2020', 'usable': 0}, {'Date': '28-12-2020', 'usable': 1}, ] df = pd.DataFrame(sample_data) # 标记usable=0的行,分割出连续usable=1的组 df['group'] = (df['usable'] == 0).cumsum() # 组内填充逻辑:仅对纯usable=1的组进行双向填充,最多2个 def fill_within_group(group): if (group['usable'] == 1).all(): group['infected'] = group['infected'].ffill(limit=2).bfill(limit=2) else: # 含usable=0的组,仅保留原infected值,其余usable=1行设为NaN group['infected'] = np.where(group['usable'] == 0, group['infected'], np.nan) return group df = df.groupby('group').apply(fill_within_group) # 清理临时分组列 df = df.drop('group', axis=1) # 验证结果匹配预期 print(df.equals(df_expected)) # 输出True
代码说明:
- 分组逻辑:通过
(df['usable'] == 0).cumsum()生成组ID,每遇到一个usable=0,组ID递增,确保连续的usable=1行被分到同一组,usable=0的行单独成组。 - 组内填充:针对纯
usable=1的组,先向前填充最多2个空值,再向后填充最多2个空值,实现从有值行向前后各覆盖最多2个相邻usable=1行;含usable=0的组仅保留原有infected值,其余行设为NaN。 - 清理临时列:删除用于分组的
group列,得到符合要求的结果。
内容的提问来源于stack exchange,提问作者user13744439
相关产品推荐
相关产品推荐

