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
关键改进
- 灵活的正则匹配:先提取括号内的所有内容,再分割日期,兼容空格、末尾点号等多种格式
- 日期清洗逻辑:自动去除日期字符串末尾多余的点号,统一格式
- 智能年份补全:处理两位年份、无年份的情况,自动判断跨年并调整年份
- 高效处理:用
apply替代iterrows循环,提升运行效率 - 错误处理:用
errors='coerce'处理无效日期,返回NaT避免程序崩溃
内容的提问来源于stack exchange,提问作者sdave
相关产品推荐
相关产品推荐

