如何在Python Pandas中为两列组合生成指定额外行
问题描述
输入数据集
我在Python Pandas中有如下DataFrame:
import pandas as pd data = [ (1, '2023-10-10', '2023-09-25', 1, 20, 11), (1, '2023-10-10', '2023-10-04', 0, 10, 10), (1, '2023-05-05', '2023-05-01', 0, 10, None), (2, '2023-02-13', '2023-02-10', 0, 25, 10), (2, '2023-02-13', '2023-02-02', None, 12, None) ] df = pd.DataFrame(data, columns=['id', 'survey', 'event', 'col1', 'col2', 'col3'])

数据集字段说明
- id:客户ID
- survey:调研日期(数据类型为object)
- event:事件日期(数据类型为object)
- col1、col2、col3:其他变量(实际数据集包含更多此类变量)
需求
需要为id和survey的每个组合生成新行,要求:
id和survey列保持原有值不变col1、col2、col3列填充NaN值event列填充该id和survey组合中不存在的日期,范围从survey日期向前回溯至前一个月的对应日期(例如id=1且survey='2023-10-10'时,event需包含2023-10-10至2023-09-10的所有日期,假设每个月都有31天)- 统一假设每个月有31天,无需考虑实际月份天数
期望输出示例
为id和survey的每个组合,生成survey日期向前31天内未在event列中出现的所有日期对应的行,新行的col1、col2、col3列填充NaN:
data = [ (1, '2023-10-10', '2023-09-25', 1, 20, 11), (1, '2023-10-10', '2023-10-04', 0, 10, 10), (1, '2023-10-10', '2023-10-09', None, None, None), ... (2, '2023-02-13', '2023-01-13', None, None, None) ] df = pd.DataFrame(data, columns=['id', 'survey', 'event', 'col1', 'col2', 'col3'])
解决方案
可以通过以下步骤实现需求:
步骤1:转换日期列类型
先将survey和event列转为datetime类型,方便后续日期运算:
df['survey'] = pd.to_datetime(df['survey']) df['event'] = pd.to_datetime(df['event'])
步骤2:生成每个(id, survey)组合的完整日期范围
按id和survey分组,为每个分组生成从survey日期减31天到survey日期的所有日期,并构建对应空值行:
def generate_missing_dates(group): survey_date = group['survey'].iloc[0] start_date = survey_date - pd.Timedelta(days=31) # 生成包含首尾的完整日期序列 date_range = pd.date_range(start=start_date, end=survey_date, freq='D') # 构建新行,id和survey沿用分组值,event为生成的日期,其余列填充NaN new_rows = pd.DataFrame({ 'id': group['id'].iloc[0], 'survey': survey_date, 'event': date_range, 'col1': None, 'col2': None, 'col3': None }) return new_rows # 对每个分组应用函数,生成完整日期对应的行 full_date_rows = df.groupby(['id', 'survey']).apply(generate_missing_dates).reset_index(drop=True)
步骤3:合并并去重,保留原数据行
将原数据与生成的空值行合并,然后按id、survey、event去重,优先保留原数据中的非空行:
# 合并原数据和生成的空值行 combined_df = pd.concat([df, full_date_rows], ignore_index=True) # 去重,保留首次出现的行(原数据行会先被保留) final_result = combined_df.drop_duplicates(subset=['id', 'survey', 'event'], keep='first') # 可选:将日期列转回原字符串格式 final_result['survey'] = final_result['survey'].dt.strftime('%Y-%m-%d') final_result['event'] = final_result['event'].dt.strftime('%Y-%m-%d')
结果说明
执行后final_result即为目标DataFrame:原有数据行全部保留,同时补充了每个(id, survey)组合中缺失的日期行,补充行的col1、col2、col3均为NaN。
内容的提问来源于stack exchange,提问作者dingaro
相关产品推荐
相关产品推荐

