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

Pandas DataFrame非固定格式日期的正则提取问题求助

解决Pandas中多格式活动日期提取问题

我有一个带Campaign列的Pandas DataFrame,该列值为「活动名称(开始日期 - 结束日期)」格式,需要提取日期生成start_date、end_date、days_between_start_and_end_date三个新列。现有代码仅能处理部分格式,对多种非固定格式的日期提取会返回NaN值。

示例数据

  • Sales is on (30.12.21-12.01.2022)
  • Sn 2 Fol CAMPAIGN A (24.03-30.03.2023)
  • M SALE (19.04 - 04.05.2022)
  • NEW SALE (29.12.2022-11.01.2023)
  • Year End (18.12. - 12.01.2023)
  • XMAS 1 - THE TRIBE CELEBRATES XMAS (18.11.-08.12.2021) (gifting communities)
  • Year End (18.12. - 12.01.2023)

现有代码问题

原代码的正则表达式仅匹配(\d+\.\d+)\.\s*-\s*(\d+\.\d+\.\d+)格式,无法兼容:

  • 日期间的空格(如19.04 - 04.05.2022)
  • 起始日期末尾的点号(如18.12. - 12.01.2023)
  • 起始日期的两位年份(如30.12.21)
  • 起始日期带完整四位年份的情况(如29.12.2022)

导致大量日期提取失败,返回NaN。

解决方案代码

import pandas as pd
import re

# 读取数据(实际使用时替换为你的文件路径)
df = pd.read_csv("report.csv")

# 提取括号内的日期区间字符串
df['date_range'] = df['Campaign'].str.extract(r'\((.*?)\)')[0]

# 分割起始和结束日期,兼容中间的空格
df[['start_raw', 'end_raw']] = df['date_range'].str.split(r'\s*-\s*', expand=True)

# 清洗日期字符串:去除末尾多余的点号
def clean_date(s):
    return s.rstrip('.') if not pd.isna(s) else s
df['start_raw'] = df['start_raw'].apply(clean_date)
df['end_raw'] = df['end_raw'].apply(clean_date)

# 转换结束日期(通常带完整年份)
df['end_date'] = pd.to_datetime(df['end_raw'], format='%d.%m.%Y', errors='coerce')

# 处理起始日期:补全年份,处理跨年情况
def parse_start(start_str, end_dt):
    if pd.isna(start_str) or pd.isna(end_dt):
        return pd.NaT
    parts = start_str.split('.')
    day, month = parts[0], parts[1]
    # 起始日期带年份的情况
    if len(parts) == 3:
        year = parts[2]
        # 处理两位年份(如21→2021)
        if len(year) == 2:
            year = f'20{year}'
        return pd.to_datetime(f'{day}.{month}.{year}', format='%d.%m.%Y')
    # 起始日期无年份,用结束日期年份,跨年则减1
    end_year = end_dt.year
    if int(month) > end_dt.month:
        start_year = end_year - 1
    else:
        start_year = end_year
    return pd.to_datetime(f'{day}.{month}.{start_year}', format='%d.%m.%Y')

df['start_date'] = df.apply(lambda row: parse_start(row['start_raw'], row['end_date']), axis=1)

# 计算日期间隔天数
df['days_between_start_and_end_date'] = (df['end_date'] - df['start_date']).dt.days

# 输出结果
print(df[['start_date', 'end_date', 'days_between_start_and_end_date']])

输出结果

start_date   end_date  days_between_start_and_end_date
0 2021-12-30 2022-01-12                                13
1 2023-03-24 2023-03-30                                 6
2 2022-04-19 2022-05-04                                15
3 2022-12-29 2023-01-11                                13
4 2022-12-18 2023-01-12                                25
5 2021-11-18 2021-12-08                                20
6 2022-12-18 2023-01-12                                25

关键改进

  1. 灵活的正则匹配:先提取括号内的所有内容,再分割日期,兼容空格、末尾点号等多种格式
  2. 日期清洗逻辑:自动去除日期字符串末尾多余的点号,统一格式
  3. 智能年份补全:处理两位年份、无年份的情况,自动判断跨年并调整年份
  4. 高效处理:用apply替代iterrows循环,提升运行效率
  5. 错误处理:用errors='coerce'处理无效日期,返回NaT避免程序崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 14:10:35