PAYATHON 2026

pandas 中按重复 id 的付款日期创建新列

支付老李

结论

可以用 pivot 将 payment_count 的值转成列名,并把对应的 payment_date 填入新列。转换后,每个 id 只占一行,也不需要单独计算 max('payment_count')。

result = (
    df.pivot(index='id', columns='payment_count', values='payment_date')
      .add_prefix('payment_date_')
      .reset_index()
      .rename_axis(columns=None)
)

结果如下:

   id payment_date_1 payment_date_2
0   1       2/2/2020       4/6/2020
1   2      3/20/2020      3/29/2020
2   3       5/1/2020      5/30/2020

完整示例

创建原始 DataFrame 时,payment_count 需要写成列表:

import pandas as pd

df = pd.DataFrame({
    'id': [1, 1, 2, 2, 3, 3],
    'payment_count': [1, 2, 1, 2, 1, 2],
    'payment_date': [
        '2/2/2020',
        '4/6/2020',
        '3/20/2020',
        '3/29/2020',
        '5/1/2020',
        '5/30/2020'
    ]
})

result = (
    df.pivot(
        index='id',
        columns='payment_count',
        values='payment_date'
    )
    .add_prefix('payment_date_')
    .reset_index()
    .rename_axis(columns=None)
)

print(result)

各项操作的作用如下:

  • index='id':让每个 id 在结果中只占一行。
  • columns='payment_count':将付款序号 1、2 等转成列。
  • values='payment_date':用付款日期填充新列。
  • add_prefix('payment_date_'):生成 payment_date_1、payment_date_2 等列名。
  • reset_index():将 id 从索引恢复为普通列。

列数会随最大的 payment_count 自动增加。例如,数据中出现 payment_count=3 时,结果会自动新增 payment_date_3。

日期类型的处理

如果后续需要按日期排序、比较日期或计算时间间隔,最好先把字符串转换为日期类型:

df['payment_date'] = pd.to_datetime(
    df['payment_date'],
    format='%m/%d/%Y'
)

转换后执行相同的 pivot 操作即可。如果需要按原格式输出,可以再进行格式化:

date_columns = result.columns.drop('id')

result[date_columns] = result[date_columns].apply(
    lambda col: col.dt.strftime('%-m/%-d/%Y')
)

部分 Windows 环境不支持 %-m 和 %-d。如果代码需要跨平台运行,可以保留标准的 datetime64 类型,或者使用 %m/%d/%Y,以带前导零的格式输出日期。

存在重复记录时

pivot 要求每个 (id, payment_count) 组合最多只有一条记录。如果同一组合对应多个付款日期,执行时会抛出重复索引错误。

遇到这种情况,需要先确定记录的选择规则,再改用 pivot_table。例如,保留最晚的付款日期:

df['payment_date'] = pd.to_datetime(
    df['payment_date'],
    format='%m/%d/%Y'
)

result = (
    df.pivot_table(
        index='id',
        columns='payment_count',
        values='payment_date',
        aggfunc='max'
    )
    .add_prefix('payment_date_')
    .reset_index()
    .rename_axis(columns=None)
)

这里的 max 比较的是付款日期,不是 payment_count。如果每个 (id, payment_count) 组合原本就是唯一的,优先使用含义更直接的 pivot。

备注:内容仅供参考。