基于日期复制DataFrame行并拆分Expences字段的实现问题
解决方案
数据预处理
首先要把日期相关字段转为标准日期格式,方便后续年月比较与计算:
import pandas as pd import numpy as np # 转换日期格式(假设数据已加载为df) df['Signed_Date'] = pd.to_datetime(df['Signed_Date'], format='%B %Y') df['start_Date'] = pd.to_datetime(df['start_Date']) df['end_Date'] = pd.to_datetime(df['end_Date'])
核心处理逻辑
我们分两部分生成最终数据:一是按start_Date到end_Date的月份拆分的常规行,二是当Signed_Date与start_Date年月不一致时的额外费用行。
1. 生成月份拆分的常规行
为每个Event生成覆盖时间段内的所有月份行,并均分ticket、Revenue、expect字段:
def generate_monthly_rows(row): # 生成start到end之间的所有月份第一天(包含首尾月) date_range = pd.date_range( start=row['start_Date'].replace(day=1), end=row['end_Date'].replace(day=1), freq='MS' ) month_count = len(date_range) # 复制行并均分数值字段 split_row = row.copy() split_row['ticket'] = row['ticket'] / month_count if pd.notna(row['ticket']) else np.nan split_row['Revenue'] = row['Revenue'] / month_count if pd.notna(row['Revenue']) else np.nan split_row['expect'] = row['expect'] / month_count if pd.notna(row['expect']) else np.nan split_row['Expences'] = 0 # 原费用将移到额外行 # 生成每行的Event_Date:首月用start_Date,其余用当月第一天 event_dates = [row['start_Date']] + list(date_range[1:]) # 组装多行数据 rows = [] for ed in event_dates: temp = split_row.copy() temp['Event_Date'] = ed rows.append(temp) return pd.DataFrame(rows) # 应用到所有行并合并结果 monthly_df = pd.concat([generate_monthly_rows(row) for _, row in df.iterrows()], ignore_index=True)
2. 生成额外费用行(年月不一致时)
筛选出Signed_Date与start_Date年月不同的记录,生成单独的费用行:
# 筛选需要生成额外行的记录 diff_month_mask = (df['Signed_Date'].dt.to_period('M') != df['start_Date'].dt.to_period('M')) extra_rows = df[diff_month_mask].copy() # 设置数值字段为0,保留原Expences值 extra_rows['ticket'] = 0 extra_rows['Revenue'] = 0 extra_rows['expect'] = 0 # 生成Event_Date为Signed_Date当月第一天 extra_rows['Event_Date'] = extra_rows['Signed_Date'].replace(day=1)
3. 合并数据并整理
把常规拆分行和额外行合并,按Event_ID与Event_Date排序:
final_df = pd.concat([monthly_df, extra_rows], ignore_index=True) # 排序并调整列顺序 final_df = final_df.sort_values(by=['Event_ID', 'Event_Date'], ignore_index=True) final_df = final_df[['Event_ID', 'ticket', 'Revenue', 'Expences', 'expect', 'Signed_Date', 'start_Date', 'end_Date', 'Event_Date']] # 格式化数值为两位小数(匹配示例格式) final_df[['ticket', 'Revenue', 'Expences', 'expect']] = final_df[['ticket', 'Revenue', 'Expences', 'expect']].round(2)
结果示例
运行后,G-00002的输出与需求示例一致:
| Event_ID | ticket | Revenue | Expences | expect | Signed_Date | start_Date | end_Date | Event_Date |
|---|---|---|---|---|---|---|---|---|
| G-00002 | 3.00 | 28.00 | 0.00 | 50.00 | 2021-05-01 | 2021-06-13 | 2021-07-13 | 2021-06-13 |
| G-00002 | 3.00 | 28.00 | 0.00 | 50.00 | 2021-05-01 | 2021-06-13 | 2021-07-13 | 2021-07-01 |
| G-00002 | 0.00 | 0.00 | 18.00 | 0.00 | 2021-05-01 | 2021-06-13 | 2021-07-13 | 2021-05-01 |
原代码问题说明
你之前的代码仅复制了指定索引的单行,未批量处理所有符合条件的记录,也未实现字段均分、月份拆分等核心逻辑,上述方案完整覆盖了所有需求点。
内容的提问来源于stack exchange,提问作者rra
相关产品推荐
相关产品推荐

