我的用户案例是检查客户(帐户)在过去30天内是否已经在同一magasin(商店)中购买了东西(如果是),那么将其在该magasin中购买的时间保存在新列中[HAS_BOUGHT_30_DAYS_AGO] 例如我拥有的数据框是这样的:
df=pd.DataFrame({'date':['2019-07-20','2019-07-29','2019-07-03','2019-08-20','2019-08-24','2019-08-05','2019-07-07','2019-06-23'],'account':['0410','0412','0410','0410','0412','0410','0410','0410'],'store':['amazon','carrefour','amazon','zara','carrefour','carrefour','auchan','amazon']})
df['date']=pd.to_datetime(df['date'])
date account store
0 2019-07-20 0410 amazon
1 2019-07-29 0412 carrefour
2 2019-07-03 0410 amazon
3 2019-08-20 0410 zara
4 2019-08-24 0412 carrefour
5 2019-08-05 0410 carrefour
6 2019-07-07 0410 auchan
7 2019-06-23 0410 amazon
我的方法是:
for transaction in df.itertuples():
delta=transaction.date-df.date
trans_before=df.loc[(df.account== transaction.account) & (delta.dt.days>0) & (delta.dt.days<30) &(df.store== transaction.store)]
df.loc[transaction.Index,'HAS_BOUGHT_30_DAYS_AGO']= len(trans_before)
我得到了结果:
date account store HAS_BOUGHT_30_DAYS_AGO
0 2019-07-20 0410 amazon 2.0
1 2019-07-29 0412 carrefour 0.0
2 2019-07-03 0410 amazon 1.0
3 2019-08-20 0410 zara 0.0
4 2019-08-24 0412 carrefour 1.0
5 2019-08-05 0410 carrefour 0.0
6 2019-07-07 0410 auchan 0.0
7 2019-06-23 0410 amazon 0.0
此方法有效,但是对于我的大型数据集(我有14837843行),它花费了很多时间,请问有人有更快的解决方案吗?
答案 0 :(得分:0)
您的问题出在df.loc
中,它可以有效地对数据框进行笛卡尔乘积运算。它为每一行迭代整个数据帧,这意味着时间复杂度实际上为O(n ^ 2)。因此,随着数据的增长,不仅会减慢for循环的速度,而且每次减慢的速度也会变慢。
为使此类查询更有效,您可能希望在(account, date)
上建立索引,或对记录进行相应的排序。我假设交易比帐户多,因此这将缩小您要搜索单个帐户的空间,并减少对O(log n)的查找。我不确定如何在Pandas中执行此操作,但是如果您的记忆允许,则可以简单地使用Python列表和字典。
另一种方法是将数据存储在关系数据库中,并使用SQL进行查询(当然是在创建索引之后)。
答案 1 :(得分:0)
使用DataFrame.sort_values
对列date
上的数据帧的值进行排序。然后在列account, store
上使用DataFrame.groupby
,并使用自定义Lambda函数date
转换列f
:
f = lambda x: x.diff().dt.days.cumsum().between(0, 30).cumsum()
df['HAS_BOUGHT'] = df.sort_values('date').groupby(['account', 'store'])['date'].apply(f)
结果:
date account store HAS_BOUGHT
0 2019-07-20 0410 amazon 2
1 2019-07-29 0412 carrefour 0
2 2019-07-03 0410 amazon 1
3 2019-08-20 0410 zara 0
4 2019-08-24 0412 carrefour 1
5 2019-08-05 0410 carrefour 0
6 2019-07-07 0410 auchan 0
7 2019-06-23 0410 amazon 0