You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于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相等、二者同属首个提取月份等。

原代码问题分析

  1. 未处理y_date所在月份的拆分逻辑,直接将整月归为adhoc或real
  2. 月末日期计算错误(用relativedelta(day=31)会导致2月等短月份日期异常)
  3. 未适配x_date和y_date同属一个月的特殊情况
  4. 使用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)

关键修改说明

  1. 正确生成月份列表:通过循环逐月生成月份起始日期,避免手动计算月数的误差
  2. 精准计算月末日期:用(month_start + relativedelta(months=1)) - relativedelta(days=1)获取当月最后一天,适配所有月份
  3. 拆分y_date所在月份:判断当前月份为y_date所在月时,自动拆分出adhoc和real两个区间并分别赋值
  4. 适配特殊场景:
    • 当x_date与y_date同属一个月时,自动拆分区间(若x_date < y_date),否则直接存入real列
    • 所有区间自动限制在next_month_day范围内
  5. 优化效率:用列表收集结果后转为DataFrame,替代效率低下的df.append()方法

内容的提问来源于stack exchange,提问作者HaRambe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 13:30:32