我有一个数据框,我想找到同一 ID 的定期付款(仅当金额相同且当月日期相同且有误差范围(+-5 天)时)。 我做了以下事情:
d = {'id':[1,1,1,3,3,3,5,5,5],
'day_of_month':[2,2,5,4,6,8,10,15,25],
'amount':[1000,1000,50,1500,3000,1500,4000,2000,2000]}
dd = pd.DataFrame(d)
print(dd)
id day_of_month amount
0 1 2 1000
1 1 2 1000
2 1 5 50
3 3 4 1500
4 3 6 3000
5 3 8 1500
6 5 10 4000
7 5 15 2000
8 5 25 2000
然后我这样做:
dd[dd.duplicated(subset = ['id','amount'], keep = False)]
id day_of_month amount
0 1 2 1000
1 1 2 1000
3 3 4 1500
5 3 8 1500
7 5 15 2000
8 5 25 2000
正如您所看到的,输出的最后一行是误报,因为我还没有设法实现当月的 +-5 天窗口。 我想要的输出应该是这样的
id day_of_month amount
0 1 2 1000
1 1 2 1000
3 3 4 1500
5 3 8 1500
关于如何实现我需要的有什么想法吗?谢谢!
为什么不添加另一个
mask
?
您的原创
mask
:
non_duplicates_mask = dd.duplicated(subset = ['id','amount'], keep = False)
月份
mask
:
months_mask = abs(dd['day_of_month'] - dd['day_of_month'].shift()) >= 5
我使用
abs
只是为了防止 day_of_month
并不总是按升序排列,
然后对两个蒙版进行
xor
操作:
dd[non_duplicates_mask ^ months_mask]
输出:
id day_of_month amount
0 1 2 1000
1 1 2 1000
3 3 4 1500
5 3 8 1500
编辑:
xor
(异或)的运作方式如下:
为您提供很大灵活性的另一种选择是使用带有聚合的 groupby。
d = {'id':[1,1,1,3,3,3,5,5,5],
'day_of_month':[2,2,5,4,6,8,10,15,25],
'amount':[1000,1000,50,1500,3000,1500,4000,2000,2000]}
dd = pd.DataFrame(d)
someDF = dd.groupby(by=['id','amount'])\
.agg({"day_of_month":['median', 'std', 'count']}).reset_index(drop=False)
# filter on those with duplicates
someDF = someDF[someDF[("day_of_month", "count")] > 1]
现在您可以使用任意数量的统计方法来确定该月的某一天是否“足够接近”。
id amount day_of_month
median std count
1 1 1000 2.0 0.000000 2
2 3 1500 6.0 2.828427 2
4 5 2000 20.0 7.071068 2
您当前的过滤器表明标准差小于 3 就构成“足够接近”。 对于较大的数据集(其中有很多重复项,通常分布在平均值周围),您可以使用变换函数将其与组平均值的距离或 PDF 计算写回每个记录,然后基于此进行过滤。