如何基于DataFrame多日期条件生成月度首尾日期分栏结果并修复循环问题?
解决日期区间拆分与多列赋值问题
需求回顾
我有一个包含x_date、y_date和next_month_day三列的DataFrame,需按以下规则拆分日期区间并赋值到对应列:
- y_date所在月份之前的月份:将当月的起始(x_date所在月从x_date开始,其余月份从当月1日开始)到当月结束的日期存入
first_date_adhoc和last_date_adhoc - y_date所在月份:拆分为两部分:
- 当月首日到
y_date前一日:存入first_date_adhoc和last_date_adhoc y_date到当月末日:存入first_date_real和last_date_real
- 当月首日到
- y_date所在月份之后的月份:将当月1日到当月结束(不超过
next_month_day)的日期存入first_date_real和last_date_real
需覆盖特殊场景:x_date与y_date相等、二者同属首个提取月份等。
原代码问题分析
- 未处理
y_date所在月份的拆分逻辑,直接将整月归为adhoc或real - 月末日期计算错误(用
relativedelta(day=31)会导致2月等短月份日期异常) - 未适配
x_date和y_date同属一个月的特殊情况 - 使用
df.append()效率低下,且未正确收集每行输入的结果
修正后的代码
import pandas as pd from dateutil.relativedelta import relativedelta def process_date_row(row): x_date = pd.to_datetime(row['x_date']) y_date = pd.to_datetime(row['y_date']) next_month_day = pd.to_datetime(row['next_month_day']) # 生成所有需要处理的月份起始日期列表 current_month = x_date.replace(day=1) month_starts = [] while current_month < next_month_day: month_starts.append(current_month) current_month += relativedelta(months=1) result_rows = [] for month_start in month_starts: # 计算当月实际结束日期:不超过next_month_day,且为当月最后一天 month_end = (month_start + relativedelta(months=1)) - relativedelta(days=1) month_end = min(month_end, next_month_day - relativedelta(days=1)) # 处理第一个月的起始日期:x_date所在月从x_date开始,其余从当月1日开始 period_start = x_date if month_start == x_date.replace(day=1) else month_start y_month_start = y_date.replace(day=1) if month_start < y_month_start: # y_date之前的月份:全量存入adhoc列 result_rows.append({ 'first_date_adhoc': period_start, 'last_date_adhoc': month_end, 'first_date_real': None, 'last_date_real': None }) elif month_start == y_month_start: # y_date所在月份:拆分两个区间 # 第一部分:adhoc区间(到y_date前一天) adhoc_end = y_date - relativedelta(days=1) if period_start <= adhoc_end: result_rows.append({ 'first_date_adhoc': period_start, 'last_date_adhoc': adhoc_end, 'first_date_real': None, 'last_date_real': None }) # 第二部分:real区间(从y_date开始) real_start = y_date if real_start <= month_end: result_rows.append({ 'first_date_adhoc': None, 'last_date_adhoc': None, 'first_date_real': real_start, 'last_date_real': month_end }) else: # y_date之后的月份:全量存入real列 result_rows.append({ 'first_date_adhoc': None, 'last_date_adhoc': None, 'first_date_real': period_start, 'last_date_real': month_end }) return pd.DataFrame(result_rows) # 示例调用 df_with_dates = pd.DataFrame({ 'x_date': ['2023-02-13', '2023-04-15', '2023-01-05'], 'y_date': ['2023-04-15', '2023-04-15', '2023-01-05'], 'next_month_day': ['2023-07-01', '2023-07-01', '2023-03-01'] }) # 处理每一行并合并最终结果 final_result = pd.concat([process_date_row(row) for _, row in df_with_dates.iterrows()], ignore_index=True) print(final_result)
关键修改说明
- 正确生成月份列表:通过循环逐月生成月份起始日期,避免手动计算月数的误差
- 精准计算月末日期:用
(month_start + relativedelta(months=1)) - relativedelta(days=1)获取当月最后一天,适配所有月份 - 拆分y_date所在月份:判断当前月份为y_date所在月时,自动拆分出adhoc和real两个区间并分别赋值
- 适配特殊场景:
- 当x_date与y_date同属一个月时,自动拆分区间(若x_date < y_date),否则直接存入real列
- 所有区间自动限制在
next_month_day范围内
- 优化效率:用列表收集结果后转为DataFrame,替代效率低下的
df.append()方法
内容的提问来源于stack exchange,提问作者HaRambe
相关产品推荐
相关产品推荐

