如何计算DataFrame中两日期列的已完成月份差值?
嘿,这个问题我熟!你遇到的报错是因为relativedelta本身是用来处理单个日期对象的,直接丢给Pandas Series肯定会出问题——它没办法判断整个Series的布尔真值,所以才抛出了那个模糊错误。
咱们一步步来解决这个计算已完成月份差的需求:
第一步:先把字符串日期转成Pandas datetime类型
你的原始数据里,dob是月/日/年格式,paymentDate是年月日数字串,得先把它们转换成Pandas能识别的日期类型,同时处理空值:
import pandas as pd from dateutil import relativedelta # 先构造你的示例数据 data = {'dob': {0: pd.NA, 1: '10/16/1988', 2: pd.NA, 3: pd.NA, 4: pd.NA}, 'paymentDate': {0: '20120501', 1: '20100602', 2: '20110601', 3: '20120501', 4: '20110101'}} df = pd.DataFrame(data) # 转换日期列,指定格式避免解析错误 df['dob'] = pd.to_datetime(df['dob'], format='%m/%d/%Y', errors='coerce') df['paymentDate'] = pd.to_datetime(df['paymentDate'], format='%Y%m%d', errors='coerce')
第二步:计算已完成的月份差
这里有两种方法,选哪种看你的数据量:
方法1:自定义函数+apply(直观,适合小数据集)
我们写一个函数,逐行处理日期对,用relativedelta计算年和月的差,再根据日期的日部分判断是否要减去1个月(比如付款日早于出生日期的日,说明当月还没走完,不算完整月份):
def get_full_months(row): dob = row['dob'] pay_date = row['paymentDate'] # 只要有一个日期是空的,就返回空值 if pd.isna(dob) or pd.isna(pay_date): return pd.NA delta = relativedelta.relativedelta(pay_date, dob) total_months = delta.years * 12 + delta.months # 如果付款日的日数小于出生日期的日数,说明当月还没完成,减1 if pay_date.day < dob.day: total_months -= 1 return total_months # 应用到每一行 df['difference_in_months'] = df.apply(get_full_months, axis=1)
方法2:矢量化计算(高效,适合大数据集)
如果你的数据量很大,apply效率会偏低,用Pandas的矢量化操作更快:
# 计算年差和月差 year_diff = df['paymentDate'].dt.year - df['dob'].dt.year month_diff = df['paymentDate'].dt.month - df['dob'].dt.month # 检查日部分:付款日 < 出生日期的日,标记为1(需要减1个月) day_adjustment = (df['paymentDate'].dt.day < df['dob'].dt.day).astype(int) # 计算总月份差 df['difference_in_months'] = year_diff * 12 + month_diff - day_adjustment # 把有缺失值的行重置为NaN df['difference_in_months'] = df['difference_in_months'].where(df['dob'].notna() & df['paymentDate'].notna(), pd.NA)
验证结果
运行完上面的代码后,你会得到预期的结果:
dob paymentDate difference_in_months 0 NaT 2012-05-01 NaN 1 1988-10-16 2010-06-02 259 2 NaT 2011-06-01 NaN 3 NaT 2012-05-01 NaN 4 NaT 2011-01-01 NaN
完全符合你要的第二行结果259~
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

