Pandas将日期差数值转换为精确到天的年月日可读文本格式
Pandas 计算日期间隔并转年/月/日文本格式
问题背景
现有客户购买记录DataFrame结构如下:
cust_id,purchase_date 1,10/01/1998 1,10/12/1999 2,13/05/2016 3,14/02/2018 3,15/03/2019
原有实现代码直接用固定365天做除法,输出十进制小数的间隔值,不符合要求:
from datetime import timedelta df['purchase_date'] = pd.to_datetime(df['purchase_date']) gb = df_new.groupby(['unique_key']) df_cust_age = gb['purchase_date'].agg(min_date=np.min, max_date=np.max).reset_index() df_cust_age['diff_in_days'] = df_cust_age['max_date'] - df_cust_age['min_date'] df_cust_age['years_diff'] = df_cust_age['diff_in_days']/timedelta(days=365)
需求明细
- 按客户ID分组,计算每个客户最早、最晚购买日期的间隔
- 时间差禁止输出十进制小数,需转换为精确到天的年、月、日拼接文本格式
- 自动匹配单复数单位(数值为1时用单数单位
year/month/day,其余情况用复数单位) - 目标输出效果:
cust_id,years_diff 1, 1 years and 11 months and 0 day 2, 0 years 3, 1 year and 1 month and 1 day
实现方案
使用dateutil.relativedelta按自然年月计算精确间隔,自定义格式化函数处理单复数和拼接逻辑:
import pandas as pd import numpy as np from dateutil.relativedelta import relativedelta # 1. 加载并解析日期,注意原始日期为日/月/年格式,需指定dayfirst避免解析错误 df = pd.DataFrame({ 'cust_id': [1,1,2,3,3], 'purchase_date': ['10/01/1998','10/12/1999','13/05/2016','14/02/2018','15/03/2019'] }) df['purchase_date'] = pd.to_datetime(df['purchase_date'], dayfirst=True) # 2. 分组计算每个客户的最早、最晚购买日期 df_cust_age = df.groupby('cust_id')['purchase_date'].agg( min_date=np.min, max_date=np.max ).reset_index() # 3. 定义时间差格式化函数 def format_date_gap(start_date, end_date): gap = relativedelta(end_date, start_date) text_parts = [] # 拼接年部分 if gap.years: unit = 'year' if gap.years == 1 else 'years' text_parts.append(f"{gap.years} {unit}") # 拼接月部分 if gap.months: unit = 'month' if gap.months == 1 else 'months' text_parts.append(f"{gap.months} {unit}") # 拼接日部分 if gap.days: unit = 'day' if gap.days == 1 else 'days' text_parts.append(f"{gap.days} {unit}") # 处理无间隔(仅1条购买记录)的情况 if not text_parts: return "0 years" # 用and拼接各部分 return ' and '.join(text_parts) # 4. 生成最终格式列 df_cust_age['years_diff'] = df_cust_age.apply( lambda row: format_date_gap(row['min_date'], row['max_date']), axis=1 ) # 提取结果列 result = df_cust_age[['cust_id', 'years_diff']] print(result)
运行结果
cust_id years_diff 0 1 1 year and 11 months and 0 day 1 2 0 years 2 3 1 year and 1 month and 1 day
说明:相比固定按365天折算年的方式,
relativedelta按自然日历规则计算间隔,不会出现闰年、大小月导致的计算偏差。如果需要严格匹配示例里1 years的写法,只需修改单复数判断逻辑即可。
内容的提问来源于stack exchange,提问作者The Great
相关产品推荐
相关产品推荐

