pandas:在时间间隔内矢量化计数行

时间:2014-08-30 21:08:14

标签: python pandas

我的情况如下。我有一个A类事件系列(a_series),由PersonID索引,另一个ID与问题无关:

PersonID      AnotherID
19            768           2013-02-03 13:39:00
              767           2013-02-03 14:03:00
              766           2013-02-03 15:35:00
              765           2013-02-03 22:32:00
              764           2013-02-04 11:36:00
              763           2013-02-04 12:07:00
26            762           2013-02-18 13:21:00
...
730           66901         2014-08-21 21:09:00
              67078         2014-08-22 23:44:00
              67141         2014-08-23 11:16:00
              67168         2014-08-23 14:53:00
              67216         2014-08-23 21:45:00
Name: Timestamp, Length: 34175, dtype: datetime64[ns]

我还有另一个系列(b_series),构建完全相同,但描述了B类事件:

PersonID      AnotherID
26            939       2013-02-18 06:01:00
              940       2013-02-18 06:47:00
              941       2013-02-19 07:02:00
...
728           65159     2014-08-14 18:40:00
729           66104     2014-08-18 09:08:00
              66229     2014-08-18 17:31:00
Name: Timestamp, Length: 1886, dtype: datetime64[ns]

请注意,虽然结构相同,但索引不相同 - 意味着某个人可能拥有的事件A多于事件B,并且可能根本没有特定类型的事件。

我想创建一个具有相同a_series结构的系列,但是对于每一行,计算在A事件发生前12小时发生的b_series中的事件数。例如,如果我们从26 762 2013-02-18 13:21:00获取行series_a,则其值应为2.

我设法通过申请这样做:

def apply_func(x, series_b):
    try:
        return series_b.loc[x['PersonID']].\
            between(x['Timestamp'] - timedelta(hours = 12), x['Timestamp']).sum()
    except KeyError:
        return 0

new_series = series_a.apply(apply_func, axis = 1, args = (seriesb,))
new_series.index = series_a.index

但我不禁觉得必须有一种更有效率的“熊猫”方式。也许用groupby或者查找?

1 个答案:

答案 0 :(得分:1)

根据框架的大小和匹配数量, 可以更有效地使用连接操作:

首先,提供系列名称并将其更改为数据框:

>>> a.name, b.name = 'a', 'b'
>>> xb = b.reset_index(level=-1).filter('b')
>>> xa = a.reset_index()

然后,加入'PersonID'

>>> df = xa.join(xb, on='PersonID', how='inner')
>>> df
   PersonID  AnotherID                   a                   b
6        26        762 2013-02-18 13:21:00 2013-02-18 06:01:00
6        26        762 2013-02-18 13:21:00 2013-02-18 06:47:00
6        26        762 2013-02-18 13:21:00 2013-02-19 07:02:00

现在,计算点击次数:

>>> lag = np.timedelta64(12, 'h')
>>> df['cnt'] = (df['b'] < df['a']) & (df['a'] < df['b'] + lag)
>>> ts = df.groupby(['PersonID', 'AnotherID', 'a'])['cnt'].sum()
>>> ts
PersonID  AnotherID  a                  
26        762        2013-02-18 13:21:00    2
Name: cnt, dtype: float64

并与原始系列对齐:

>>> xcol = ['PersonID', 'AnotherID', 'a']
>>> xa.join(ts, on=xcol).fillna(0).set_index(xcol[:-1])
                                     a  cnt
PersonID AnotherID                         
19       768       2013-02-03 13:39:00    0
         767       2013-02-03 14:03:00    0
         766       2013-02-03 15:35:00    0
         765       2013-02-03 22:32:00    0
         764       2013-02-04 11:36:00    0
         763       2013-02-04 12:07:00    0
26       762       2013-02-18 13:21:00    2
730      66901     2014-08-21 21:09:00    0
         67078     2014-08-22 23:44:00    0
         67141     2014-08-23 11:16:00    0
         67168     2014-08-23 14:53:00    0
         67216     2014-08-23 21:45:00    0