You need to enable JavaScript to run this app. pandas如何通过滚动函数实现客户发票付款状态校验?
优惠活动
大模型
产品
解决方案
定价
更多

pandas如何通过滚动函数实现客户发票付款状态校验?

针对发票付款状态校验的pandas高效实现方案

你这类同分组内跨相邻行交叉字段对比的需求,完全不需要硬套rolling()实现,反而用向量化的分组移位、累计聚合的方法,性能会比自定义滚动函数高几个量级,也是pandas生态里处理这类问题的标准做法。


前置数据预处理

你当前的日期字段是day X格式的字符串,直接做大小比较会走字典序匹配,结果不准,第一步先把可比较的日期数值抽出来,再按客户、发票开具时间排序:

import pandas as pd
import numpy as np

# 加载原始测试数据
data = [
          ['day 1','day 2', 2, 50],
          ['day 2','day 4', 2, 60],
          ['day 3','day 3', 1, 45],
          ['day 4','day 7', 2, 45],
          ['day 5','day 10', 3, 90],
          ['day 6','day 7', 3, 10],
          ['day 7','day 8', 2, 10]
]
columns = ['invoicedate', 'paymentdate', 'clientid', 'amounts']
df = pd.DataFrame(data=data, columns=columns)

# 预处理:从日期字符串里提取纯数字,转成可比较的整数
df['inv_day'] = df['invoicedate'].str.extract(r'(\d+)').astype(int)
df['pay_day'] = df['paymentdate'].str.extract(r'(\d+)').astype(int)
# 按客户ID、发票开单日排序,保证同客户的发票按开单先后顺序排列
df = df.sort_values(['clientid', 'inv_day']).reset_index(drop=True)

核心需求实现:校验开新票时上一张发票是否已完成付款

你的校验逻辑本质是:对每个客户按开单顺序排列的发票记录,拿当前行的开单日,对比同客户上一张发票的付款日——如果上一张的付款日早于当前新票的开单日,就说明开新票时旧账已经结清。
这个逻辑完全可以用分组移位实现,不需要滚动窗口:

# 按客户分组,提取同客户上一张发票的付款日,对齐到当前新票行
client_group = df.groupby('clientid')
df['prev_invoice_pay_day'] = client_group['pay_day'].shift(1)

# 校验规则:上一张发票的付款完成日 < 当前新票的开单日 → 满足「开新票前旧账已结清」
df['is_prev_paid_before_new_invoice'] = df['prev_invoice_pay_day'] < df['inv_day']

实现说明

  • groupby.shift(1) 是纯向量化操作,对百万级数据的处理速度比滚动窗口加自定义函数快10倍以上
  • 每个客户的第一张发票因为没有上一张记录,移位后的值为空,属于正常的初始状态
  • 你之前尝试用rolling()没跑通,大概率是两个常见问题:
    • 没有按客户分组单独开滚动窗口,直接在全表上滚动,导致跨客户对比了无关记录
    • pandas默认的单列滚动函数只能传入当前列的序列值,没法在窗口内跨多列取值,写自定义函数传多列的开销会非常大

拓展场景:开新票时检查所有历史发票是否存在未结清

如果你的需求升级为不管隔了多少张旧发票,只要开新票的时间点还有任何一张旧发票没付完,就算存在风险,这时候也不需要硬写滚动函数,用累计最大值的向量化方法就能搞定:

# 计算同客户累计到当前行的历史最大付款日(移位后就变成「上一张及更早的所有发票的最大付款日」)
df['hist_max_pay_day'] = client_group['pay_day'].cummax().shift(1)
# 如果历史最大付款日 > 当前新票开单日 → 说明有旧发票的付款时间晚于新票开单时间,存在未结清
df['has_unpaid_old_invoice'] = df['hist_max_pay_day'] > df['inv_day']

这种实现和全量滚动逐行检查的结果完全一致,但全程没有用循环或者自定义apply,计算效率比rolling方案高两个量级。


内容的提问来源于stack exchange,提问作者Bernar van Tongeren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.03 14:15:04