如何递归遍历DataFrame并计算行值?补全缺失的start与end字段
解决DataFrame中按规则递推计算start和end字段的问题
问题背景
原始DataFrame定义如下:
import pandas as pd list_columns = ['id','start', 'end', 'duration'] list_data = [ [1,'2023-01-01', '2023-04-02', 0], [2,'2023-01-10', 0, 2], [3,'0', 0, 3], [4,'0', 0, 4] ] df = pd.DataFrame(columns=list_columns, data=list_data)
需求规则:
- 针对每行数据,若
start或end的值为'0'或数字0,则按规则计算填充 - 若
start为待填充状态(0/'0'),则取上一行已确定的end值作为当前行的start - 当前行的
end值 = 当前行的start+ 当前行的duration(duration为天数,需与日期类型匹配)
解决方案
首先统一处理数据类型:将start/end转换为日期类型,把0或'0'替换为NaN(标记为待填充值)。
方法一:迭代遍历(推荐,高效易维护)
迭代是处理这类递推问题最直接高效的方式,逐行计算并填充:
import pandas as pd from datetime import timedelta # 1. 初始化并预处理数据 list_columns = ['id','start', 'end', 'duration'] list_data = [ [1,'2023-01-01', '2023-04-02', 0], [2,'2023-01-10', 0, 2], [3,'0', 0, 3], [4,'0', 0, 4] ] df = pd.DataFrame(columns=list_columns, data=list_data) # 转换日期列,将0/'0'转为NaN df['start'] = pd.to_datetime(df['start'], errors='coerce') df['end'] = pd.to_datetime(df['end'], errors='coerce') # 2. 逐行迭代计算 for idx in range(1, len(df)): prev_row = df.iloc[idx-1] # 填充当前行start if pd.isna(df.loc[idx, 'start']): df.loc[idx, 'start'] = prev_row['end'] # 填充当前行end if pd.isna(df.loc[idx, 'end']): df.loc[idx, 'end'] = df.loc[idx, 'start'] + timedelta(days=df.loc[idx, 'duration']) print(df)
运行结果:
id start end duration 0 1 2023-01-01 2023-04-02 0 1 2 2023-01-10 2023-01-12 2 2 3 2023-01-12 2023-01-15 3 3 4 2023-01-15 2023-01-19 4
方法二:递归遍历实现
递归核心是从当前行向上追溯,确保上一行计算完成后再处理当前行:
import pandas as pd from datetime import timedelta # 初始化并预处理数据 list_columns = ['id','start', 'end', 'duration'] list_data = [ [1,'2023-01-01', '2023-04-02', 0], [2,'2023-01-10', 0, 2], [3,'0', 0, 3], [4,'0', 0, 4] ] df = pd.DataFrame(columns=list_columns, data=list_data) df['start'] = pd.to_datetime(df['start'], errors='coerce') df['end'] = pd.to_datetime(df['end'], errors='coerce') def fill_row(idx): # 基线条件:第一行无需递归 if idx == 0: return # 先递归处理上一行,确保数据已填充完成 fill_row(idx - 1) prev_row = df.iloc[idx - 1] # 填充当前行start if pd.isna(df.loc[idx, 'start']): df.loc[idx, 'start'] = prev_row['end'] # 填充当前行end if pd.isna(df.loc[idx, 'end']): df.loc[idx, 'end'] = df.loc[idx, 'start'] + timedelta(days=df.loc[idx, 'duration']) # 从最后一行触发递归填充 fill_row(len(df)-1) print(df)
运行结果与迭代方法一致。
注意:递归方法在DataFrame行数较多时可能出现栈溢出问题,仅适合小数据集;迭代方法更通用高效。
内容的提问来源于stack exchange,提问作者user3619789
相关产品推荐
相关产品推荐

