You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

周期性入账支付的重复支付检测及支付类型与金额拆解方案咨询

周期性入账支付的重复支付检测及支付类型与金额拆解方案咨询

我之前处理过类似的周期性支付流水分析需求,结合你的场景,给你梳理几个可落地的思路,既能处理无噪音的干净数据,也能应对带小额异常的情况:

一、先做数据预处理,把基础数据理清楚

首先得把数据整理成方便分析的格式:

  • 合并/拆分同日交易:像你示例里同一天有两笔不同金额的支付,先保留明细(因为是不同类型的支付),但如果是同一类型的重复入账,可以考虑合并求和,避免干扰周期计算。
  • 转换时间维度:把每笔交易的日期转换成「与首笔交易的天数差」,或者直接计算相邻交易的间隔天数,这样更容易发现周期规律。
  • 初步标记噪音:用箱线图或者简单的阈值先把明显异常的小额(比如你说的偶尔50)标记出来,后续可以单独处理,不影响周期性分析。

二、用聚类区分不同金额的支付组

因为不同类型的支付金额通常会形成明显的簇,这里推荐用DBSCAN聚类(比K-means更适合带噪音的场景),它能自动识别出异常点:

  • 设定合适的「金额距离阈值」:比如你示例里5107和1500差距很大,阈值设100就能轻松分开;如果是金额接近的不同类型(比如5000和5200),可以调小阈值。
  • 聚类后,把标记为「噪音」的簇(通常DBSCAN会给噪音点标记为-1)单独拎出来,剩下的簇就是可能的周期性支付组。

三、针对每个金额簇检测周期性

拿到每个金额对应的交易日期后,就可以找周期规律了:

  • 统计间隔天数频率:计算同一簇内相邻交易的天数差,看哪个天数出现的频率最高——比如每周支付的话,7天左右的间隔会占绝大多数;每月支付的话,28-31天的间隔会是主流。
  • 自相关分析(ACF):如果用Python的话,可以用statsmodels的ACF函数,绘制自相关图,图中峰值对应的天数就是最可能的周期(比如7天、30天的位置出现峰值)。
  • 规则匹配验证:先预设常见周期(7、14、28、30天),然后统计每个簇符合该周期的交易占比,占比超过80%的就可以确定为对应周期。

四、计算各支付类型的平均金额

确定周期和金额簇的对应关系后,就可以计算平均金额了:

  • 对同一簇内的金额取平均值,同时可以过滤掉和平均值偏差过大的点(比如偏差超过10%),避免噪音影响。
  • 比如你示例里的5107系列,去掉可能的异常后,平均下来就是每周支付的标准金额;1500的系列就是每月支付的金额。

简单代码示例(Python)

这里给你一段快速验证的代码,适合你的场景:

import pandas as pd
from sklearn.cluster import DBSCAN
import numpy as np

# 加载数据(假设你把数据存成CSV)
df = pd.read_csv('payments.csv')
df['date'] = pd.to_datetime(df['date'])

# 计算相邻交易的天数差
df['day_diff'] = df['date'].diff().dt.days.dropna()

# 对金额做DBSCAN聚类,区分不同支付类型
amount_data = df['amount'].values.reshape(-1, 1)
# eps是金额距离阈值,min_samples是最少交易次数(避免把单次支付当成一类)
dbscan = DBSCAN(eps=100, min_samples=3)
df['amount_cluster'] = dbscan.fit_predict(amount_data)

# 遍历每个簇,分析周期和平均金额
for cluster_id in df['amount_cluster'].unique():
    if cluster_id == -1:
        print(f"【噪音支付】金额列表:{df[df['amount_cluster'] == -1]['amount'].tolist()}")
        continue
    
    cluster_df = df[df['amount_cluster'] == cluster_id]
    avg_amount = round(cluster_df['amount'].mean(), 2)
    # 统计最常见的间隔天数
    top_periods = cluster_df['day_diff'].value_counts().head(2)
    
    print(f"【支付类型】平均金额:{avg_amount}")
    print(f"  最可能的周期:{top_periods.index.tolist()}天,对应出现次数:{top_periods.values.tolist()}")
    print("---")

额外注意事项

  • 区分「每4周」和「每月」:如果某类支付的间隔在28天左右,且3个月内有4笔,那更可能是每4周;如果3个月内只有3笔,那就是每月。
  • 跨月日期的处理:比如每月最后一天的支付,2月和3月的间隔是28天,3月和4月是31天,这时候可以结合月份差来辅助判断(比如每1个月出现一次)。
  • 小额周期性支付:如果偶尔的50其实是固定周期的小额支付,聚类时会形成单独的簇,这时候不要当成噪音,而是新增一类支付类型。

备注:内容来源于stack exchange,提问作者sonnysang

火山引擎 最新活动