在熊猫窗口期间有效地计算创建率

时间:2014-06-02 19:46:46

标签: python pandas

对于我的数据中的每个观察,我试图想出在过去7天内创建的观察数量。

obs       date
 A      1/1/2000
 B      1/4/2000
 C      1/5/2000
 D      1/10/2000
 E      1/20/2000
 F      1/1/2000

会变成:

obs       date       births last week
 A      1/1/2000            2
 B      1/4/2000            3
 C      1/5/2000            4
 D      1/10/2000           3
 E      1/20/2000           1
 F      1/1/2000            2

现在我正在使用以下方法,但速度非常慢:

def past_week(x,df):
    back = x['date'] - dt.timedelta(days=7)
    return df[(df['date'] >= back) & (df['date'] < x['date'])].count()

df['births_last_week'] = df.apply(lambda x: past_week(x,df),axis=1)

编辑:重复日期有困难。也许我做错了什么。我编辑了上面的例子,包括重复的日期:

df['births last week'] = df.groupby('date').cumcount() + 1
pd.rolling_count(df.set_index('date'), 7 + 1, freq='D').loc[df.date] - 1

给出:

  date      births last week            
2000-01-01        1
2000-01-04        2
2000-01-05        3
2000-01-10        3
2000-01-20        1
2000-01-01        1

我已经尝试过rolling_sum,但是我得到的就是上周出生时的NA值。我想有一些非常明显的事情,我错了,只是不确定是什么。

2 个答案:

答案 0 :(得分:3)

这是一种方法:

df = pd.read_csv("birth.csv", delim_whitespace=True, parse_dates=["date"])
by_day = df.groupby("date").count().resample("D").fillna(0)
csum = by_day.cumsum()
last_week = csum - csum.shift(7).fillna(0)
final = last_week.loc[df.date]
制造

>>> final
            obs
date           
2000-01-01    2
2000-01-04    3
2000-01-05    4
2000-01-10    3
2000-01-20    1
2000-01-01    2

一步一步,首先我们得到DataFrame(你可能已经有了):

>>> df = pd.read_csv("birth.csv", delim_whitespace=True, parse_dates=["date"])
>>> df
  obs       date
0   A 2000-01-01
1   B 2000-01-04
2   C 2000-01-05
3   D 2000-01-10
4   E 2000-01-20
5   F 2000-01-01

然后我们按日期分组,并计算观察次数:

>>> df.groupby("date").count()
            obs
date           
2000-01-01    2
2000-01-04    1
2000-01-05    1
2000-01-10    1
2000-01-20    1

我们可以将此重新采样到几天;当然,这将是一个更长的时间序列,但记忆力很便宜而且我很懒:

>>> df.groupby("date").count().resample("D")
            obs
date           
2000-01-01    2
2000-01-02  NaN
2000-01-03  NaN
2000-01-04    1
2000-01-05    1
2000-01-06  NaN
2000-01-07  NaN
2000-01-08  NaN
2000-01-09  NaN
2000-01-10    1
2000-01-11  NaN
2000-01-12  NaN
2000-01-13  NaN
2000-01-14  NaN
2000-01-15  NaN
2000-01-16  NaN
2000-01-17  NaN
2000-01-18  NaN
2000-01-19  NaN
2000-01-20    1

摆脱nans:

>>> by_day = df.groupby("date").count().resample("D").fillna(0)
>>> by_day
            obs
date           
2000-01-01    2
2000-01-02    0
2000-01-03    0
2000-01-04    1
2000-01-05    1
2000-01-06    0
2000-01-07    0
2000-01-08    0
2000-01-09    0
2000-01-10    1
2000-01-11    0
2000-01-12    0
2000-01-13    0
2000-01-14    0
2000-01-15    0
2000-01-16    0
2000-01-17    0
2000-01-18    0
2000-01-19    0
2000-01-20    1

并将累计金额作为手动滚动和过程的一部分。默认的滚动总和具有错误的对齐方式,因此我将减去一周的差异:

>>> csum = by_day.cumsum()
>>> last_week = csum - csum.shift(7).fillna(0)
>>> last_week
            obs
date           
2000-01-01    2
2000-01-02    2
2000-01-03    2
2000-01-04    3
2000-01-05    4
2000-01-06    4
2000-01-07    4
2000-01-08    2
2000-01-09    2
2000-01-10    3
2000-01-11    2
2000-01-12    1
2000-01-13    1
2000-01-14    1
2000-01-15    1
2000-01-16    1
2000-01-17    0
2000-01-18    0
2000-01-19    0
2000-01-20    1

然后选择我们关心的日期:

>>> final = last_week.loc[df.date]
>>> final
            obs
date           
2000-01-01    2
2000-01-04    3
2000-01-05    4
2000-01-10    3
2000-01-20    1
2000-01-01    2

答案 1 :(得分:1)

In [57]: df
Out[57]: 
  obs       date
0   A 2000-01-01
1   B 2000-01-04
2   C 2000-01-05
3   D 2000-01-10
4   E 2000-01-20

In [58]: df['births last week'] = 1

In [59]: pd.rolling_count(df.set_index('date'), 7 + 1, freq='D').loc[df.date] - 1
Out[59]: 
            births last week
2000-01-01                 0
2000-01-04                 1
2000-01-05                 2
2000-01-10                 2
2000-01-20                 0

我减1,因为rolling_count包含当前条目,而你不会。

编辑:要处理重复日期,如您对问题的评论中所述,按日期分组并总结上周的出生情况&#39;上面输入58和59之间的列。