Pandas DataFrame 基于月度支付数据修改date_activated列值
需求实现
核心逻辑
- 按现有列顺序筛选出所有月度支付列(列名类型为
datetime的列,即date_activated之后的所有列) - 逐行定位该行月度列中从左到右第一个数值大于0的列,取该列的列头日期作为首次支付日期(列头本身为当月第一天)
- 对比原
date_activated与首次支付日期的年月:年月一致则保留原激活日期,不一致则替换为该首次支付日期
完整可运行代码
import pandas as pd from datetime import datetime # 用你提供的字典构造原始DataFrame data = {'account_id': {0: 1, 1: 1, 2: 1}, 'contract_id': {0: 'A', 1: 'B', 2: 'C'}, 'date_activated': {0: pd.Timestamp('2020-12-04 00:00:00'), 1: pd.Timestamp('2021-03-09 00:00:00'), 2: pd.Timestamp('2021-04-25 00:00:00')}, datetime(2021, 12, 1, 0, 0): {0: 200.0, 1: 0.0, 2: 0.0}, datetime(2021, 1, 1, 0, 0): {0: 200.0, 1: 0.0, 2: 0.0}, datetime(2021, 2, 1, 0, 0): {0: 200.0, 1: 300.0, 2: 0.0}, datetime(2021, 3, 1, 0, 0): {0: 0.0, 1: 300.0, 2: 0.0}, datetime(2021, 4, 1, 0, 0): {0: 0.0, 1: 300.0, 2: 100.0}, datetime(2021, 5, 1, 0, 0): {0: 0.0, 1: 300.0, 2: 100.0}, datetime(2021, 6, 1, 0, 0): {0: 0.0, 1: 300.0, 2: 100.0}} df = pd.DataFrame(data) # 1. 筛选所有月度支付列(列名是datetime类型的列,与前3个非月度列区分) monthly_cols = [col for col in df.columns if isinstance(col, datetime)] # 2. 逐行获取该行第一个正支付对应的列日期 def get_first_pay(row): # 生成布尔掩码:月度列值>0的位置为True positive_mask = row[monthly_cols] > 0 # 存在正支付时,返回第一个True对应的列名(即最靠左的非零支付列) if positive_mask.any(): return positive_mask.idxmax() # 全零支付的场景可根据业务需求补充处理逻辑,此处默认返回空时间 return pd.NaT df['first_pay_date'] = df.apply(get_first_pay, axis=1) # 3. 按规则更新date_activated def update_activation_date(row): orig_act = row['date_activated'] first_pay = row['first_pay_date'] # 仅对比年月,一致则保留原日期 if (orig_act.year, orig_act.month) == (first_pay.year, first_pay.month): return orig_act # 不一致则替换为首次支付的月初日期 return first_pay df['date_activated'] = df.apply(update_activation_date, axis=1) # 4. 删除临时计算列 df = df.drop(columns=['first_pay_date'])
结果验证
运行后输出的date_activated列完全匹配预期:
- 第0行:原激活日期年月为
2020-12,首次支付列日期年月为2021-12,不一致,替换为2021-12-01 - 第1行:原激活日期年月为
2021-03,首次支付列日期年月为2021-02,不一致,替换为2021-02-01 - 第2行:原激活日期年月为
2021-04,首次支付列日期年月为2021-04,一致,保留原日期2021-04-25
内容的提问来源于stack exchange,提问作者Yam
相关产品推荐
相关产品推荐

