大熊猫计算过去N天的发生次数,满足特定条件

时间:2017-06-24 17:37:47

标签: pandas

假设我有以下数据框,并且我想计算出现次数" True"在过去14天内在同一类别中,我该怎么做?例如,以下数据框将生成一个值为0,1,1,0,2,0,1,0

的列
Date         Category   has_egg
2017-01-01   Lunch      True
2017-01-02   Lunch      True 
2017-01-02   Lunch      False
2017-01-02   Dinner     True
2017-01-12   Lunch      False
2017-01-13   Breakfast  False  
2017-01-13   Dinner     False
2017-02-04   Lunch      True

我尝试使用group by但无法找出确切的命令

df.groupby("Category").has_egg.count_number_of_True(time_delta(-14d)) ?

2 个答案:

答案 0 :(得分:2)

我认为只需合并resample& rolling groupby pd.to_datetime。 (请注意,下面的代码假定您的索引是正确的python / pandas日期时间。如果没有,您需要先将其转换为df.groupby('Category').resample('d').sum().fillna(0).\ groupby('Category').rolling(14,min_periods=1).sum() 。)

resample

rolling行只是纠正了每个日期/类别可以包含多于或少于一行的事实。然后,您可以非常直接地使用Lunch Lunch 2017-01-01 1.0 2017-01-02 2.0 . . . 2017-01-14 2.0 2017-01-15 1.0 2017-01-16 0.0

这是输出的一部分:

df.groupby('Category').resample('w').sum().fillna(0).\
   groupby('Category').rolling(2,min_periods=1).sum()

                                has_egg
Category  Category  Date               
Breakfast Breakfast 2017-01-15      0.0
Dinner    Dinner    2017-01-08      1.0
                    2017-01-15      1.0
Lunch     Lunch     2017-01-01      1.0
                    2017-01-08      2.0
                    2017-01-15      1.0
                    2017-01-22      0.0
                    2017-01-29      0.0
                    2017-02-05      1.0

或者,为了简明起见,这是每周一次的样子:

monitorEvents()

我认为这种方式应该非常快,尽管不是内存效率,因为它将每个日期/类别组合的数据扩展到一行。如果内存是一个问题,你想要看一些替代方法(这可能会慢一点,也不那么优雅,所以除非你的数据相当大,否则我不会担心)。

另请注意:即使您的示例数据不包含该情况,如果您对唯一日期/类别有多个True值,我相信此代码也可以正常工作。如果您能够处理该示例数据,那么您可能希望编辑该示例数据。

答案 1 :(得分:2)

这可能不是一种有效的方法,但您可以做的是,迭代每一行并构建满足要求的mask或其他dataframe,并将它们计算为更新为新{ {1}}。

column

结果# converting to pandas datetime df['Date'] = pd.to_datetime(df['Date']).dt.date print(df) 是:

df

现在,遍历每一行并查找满足所有要求的那些并总结它们:

         Date   Category has_egg
0  2017-01-01      Lunch    True
1  2017-01-02      Lunch    True
2  2017-01-02      Lunch   False
3  2017-01-02     Dinner    True
4  2017-01-12      Lunch   False
5  2017-01-13  Breakfast   False
6  2017-01-13     Dinner   False
7  2017-02-04      Lunch    True

输出:

for index, row in df.iterrows():
    mask = (df.Category == row.Category) & (df.Date > (row.Date - pd.Timedelta(days=14))) & (df.Date < row.Date) & (df.has_egg == True)
    df.loc[index, 'values'] = sum(mask) # insert to the new column

print(df)