熊猫 - 滚动窗口 - 不均匀间隔

时间:2016-05-13 18:11:33

标签: python pandas time-series

我在编制此数据集中适用于每个买家的滚动交易数量时遇到问题,结构如下:

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为条件。

2 个答案:

答案 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))