2014-08-30 78 views
1

我的情況如下。我有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] 

注意的是,雖然結構是一樣的,指數是不一樣的 - 這意味着一個人可以有更多的事件比事件B,可能不會有一定的活動鍵入。

我想創建一個具有相同結構a_series的系列,但是對於每一行,計算髮生在A事件之前12小時內的b_series的事件數量。因此,舉例來說,如果我們走線26 762 2013-02-18 13:21:00series_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或lookup?

回答

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 
+0

第一個加入實際上是笛卡爾積,對不對?我會盡力在真實數據上計時。謝謝。 – Korem 2014-08-31 15:40:38

+1

@Korem它是笛卡爾產品只有匹配的'PersonID'行,而不是兩個框架。它仍然是上述代碼的瓶頸,如果兩個系列中每個「PersonID」有很多行,則效率可能不高。 – 2014-08-31 15:46:42

+0

是的,但我的解決方案在這些條款中並沒有更好的解決方案。它遍歷完全相同數量的「行」。 – Korem 2014-08-31 15:54:45