我在编制此数据集中适用于每个买家的滚动交易数量时遇到问题,结构如下:
userID itemID transaction_ts
3229 4493320 2016-01-02 14:55:00
3229 4492492 2016-01-02 14:57:02
3229 4496756 2016-01-04 09:01:18
3229 4493673 2016-01-04 09:11:10
3229 4497531 2016-01-04 11:05:25
3229 4495006 2016-01-05 07:25:11
4330 4500695 2016-01-02 09:17:21
4330 4500656 2016-01-03 09:19:28
4330 4503087 2016-01-04 07:42:15
4330 4501846 2016-01-04 08:55:24
4330 4504105 2016-01-04 09:59:35
理想情况下,对于例如滚动事务计数窗口,它看起来如下所示。 24小时:
userID itemID transaction_ts rolling_count
3229 4493320 2016-01-02 14:55:00 1
3229 4492492 2016-01-02 14:57:02 2
3229 4496756 2016-01-04 09:01:18 1
3229 4493673 2016-01-04 09:11:10 2
3229 4497531 2016-01-04 11:05:25 3
3229 4495006 2016-01-05 07:25:11 4
4330 4500695 2016-01-02 09:17:21 1
4330 4500656 2016-01-03 09:19:28 1
4330 4503087 2016-01-04 07:42:15 2
4330 4501846 2016-01-04 08:55:24 3
4330 4504105 2016-01-04 09:59:35 3
这里有类似问题的优秀答案:pandas rolling sum of last five minutes
但是,这个答案完全取决于时间戳字段,不像上面那样,当遇到从不同用户到上一行的事务的事务时,滚动计数必须重置为1。可以通过切片找到解决方案,但是考虑到此数据集的大小(可能是1m +行),这是不可行的。
至关重要的是,窗口应该反映相应行的transactional_ts之前的24小时时段,因此我认为自定义df.apply或rolling_window方法是合适的,我只是无法弄清楚如何制作该方法以userID为条件。
答案 0 :(得分:4)
解决方案的一部分(滚动的cumsum)可能已经是here。 (我只改变了滞后的类型):
from datetime import timedelta
def msum(s, lag):
lag = s.index - timedelta(days=lag)
inds = np.searchsorted(s.index.astype(np.int64), lag.astype(np.int64))
cs = s.cumsum()
return pd.Series(cs.values - cs[inds].values + s[inds].values, index=s.index)
该函数要求索引为datetime类型。此外,每个userID组中的索引应该已经排序(例如在您的示例中)。
df = df.set_index('transaction_ts')
df['rolling_count'] = 1
df['rolling_count'] = df.groupby('userID', sort=False)['rolling_count'].transform(lambda x : msum(x,1))
groupby选项sort=False
可能会加快速度。 (它负责对组密钥进行排序。)
答案 1 :(得分:0)
我设法得到了一个解决方案,至少可以在测试集上运行。 ptjr首先到达那里!关于这个问题的第一个解决方案Pandas Rolling Computations on Sliding Windows (Unevenly spaced)帮助了很多。
正如ptrj早先指出的那样 - 使用df.groupby(' userID')是关键。
df = pd.read_excel('velocity.xlsx') # reading dataframe in
df = df.sort_values(['userID','transaction_ts'])
df = df.reset_index(drop=True) # ensure index is sorted according to userID|transaction_ts
df['ones'] = 1
def add_rolling_count(x,number_of_hours):
x['lag'] = x['transaction_ts'] - timedelta(hours=number_of_hours)
inds = np.searchsorted(np.array(x['transaction_ts'].astype(np.int64)), np.array(x['lag'].astype(np.int64)))
cs = x['ones'].reset_index(drop=True).cumsum()
x['count'] = cs.values - cs[inds].values + 1
return x`
df = df.groupby('user_id').apply(lambda x: add_rolling_count(x, 24))