Pandas - 最近 x 天的值的计数频率

Posted

技术标签:

【中文标题】Pandas - 最近 x 天的值的计数频率【英文标题】:Pandas - Count frequency of value for last x amount of days 【发布时间】:2020-06-22 08:15:04 【问题描述】:

我发现了一些意想不到的结果。我想要做的是创建一个查看 ID 号和日期的列,并计算过去 7 天内该 ID 号出现的次数(我还想将这个动态设置为 x 数量天,但只是试用 7 天)。

所以给定这个数据框:

import pandas as pd



df = pd.DataFrame(
        [['A', '2020-02-02 20:31:00'],
        ['A', '2020-02-03 00:52:00'],
        ['A', '2020-02-07 23:45:00'],
        ['A', '2020-02-08 13:19:00'],
        ['A', '2020-02-18 13:16:00'],
        ['A', '2020-02-27 12:16:00'],
        ['A', '2020-02-28 12:16:00'],
        ['B', '2020-02-07 18:57:00'],
        ['B', '2020-02-07 21:50:00'],
        ['B', '2020-02-12 19:03:00'],
        ['C', '2020-02-01 13:50:00'],
        ['C', '2020-02-11 15:50:00'],
        ['C', '2020-02-21 10:50:00']],
        columns = ['ID', 'Date'])

计算每个实例在过去 7 天内发生的代码:

df['Date'] = pd.to_datetime(df['Date'])

delta = 7
df['count_in_last_%s_days' %(delta)] = df.groupby(['ID', pd.Grouper(freq='%sD' %delta, key='Date')]).cumcount()

输出:

   ID                Date  count_in_last_7_days
0   A 2020-02-02 20:31:00                     0
1   A 2020-02-03 00:52:00                     1
2   A 2020-02-07 23:45:00                     2
3   A 2020-02-08 13:19:00                     0 #<---- This should output 3
4   A 2020-02-18 13:16:00                     0
5   A 2020-02-27 12:16:00                     0
6   A 2020-02-28 12:16:00                     1
7   B 2020-02-07 18:57:00                     0
8   B 2020-02-07 21:50:00                     1
9   B 2020-02-12 19:03:00                     0 #<---- THIS SHOULD OUTPUT 2
10  C 2020-02-01 13:50:00                     0
11  C 2020-02-11 15:50:00                     0
12  C 2020-02-21 10:50:00                     0

【问题讨论】:

您的示例仅跨越一周(在我们 groupby ID 之后),因此我们无法看到 7 天窗口正常工作。你能把你的例子放大一点,来测试一下吗? @smci,好点子。以上更新 【参考方案1】:

您不想在Date 上使用Grouper,而是使用rolling 窗口。分组器将数据帧分段为所需持续时间的单独连续块。从每个日期起您想要 7 天,这是 rolling 的工作:

delta = 7
df['count_in_last_%s_days' %(delta)] = df.assign(count=1).groupby(
    ['ID']).apply(lambda x: x.rolling('%sD' %delta, on='Date').sum(
        ))['count'].astype(int) - 1

它按预期给出:

   ID                Date  count_in_last_7_days
0   A 2020-02-02 20:31:00                     0
1   A 2020-02-03 00:52:00                     1
2   A 2020-02-07 23:45:00                     2
3   A 2020-02-08 13:19:00                     3
4   A 2020-02-18 13:16:00                     0
5   A 2020-02-27 12:16:00                     0
6   A 2020-02-28 12:16:00                     1
7   B 2020-02-07 18:57:00                     0
8   B 2020-02-07 21:50:00                     1
9   B 2020-02-12 19:03:00                     2
10  C 2020-02-01 13:50:00                     0
11  C 2020-02-11 15:50:00                     0
12  C 2020-02-21 10:50:00                     0

【讨论】:

好的,为什么会有这样的输出是有道理的。感谢您不仅提供代码,还感谢您的解释。 很好的答案。标记:rolling-computation。如果当您使用 rollingGrouper 时 pandas doc 没有充分涵盖,那么值得提交一个 docbug...【参考方案2】:

看起来像在 Date 上滚动并使用正确的窗口就可以了:

(df.set_index('Date')
   .assign(count_last=1)
   .groupby('ID')
   .rolling(f'deltaD')
   .sum() - 1
)

输出:

                        count_last
ID Date                           
A  2020-02-02 20:31:00         0.0
   2020-02-03 00:52:00         1.0
   2020-02-07 23:45:00         2.0
   2020-02-08 13:19:00         3.0
   2020-02-18 13:16:00         0.0
   2020-02-27 12:16:00         0.0
   2020-02-28 12:16:00         1.0
B  2020-02-07 18:57:00         0.0
   2020-02-07 21:50:00         1.0
   2020-02-12 19:03:00         2.0
C  2020-02-01 13:50:00         0.0
   2020-02-11 15:50:00         0.0
   2020-02-21 10:50:00         0.0

【讨论】:

以上是关于Pandas - 最近 x 天的值的计数频率的主要内容,如果未能解决你的问题,请参考以下文章

python [Pandas]基于2列的频率计数

pandas DataFrame 列中值的计数频率

具有多列的groupby,在pandas中具有添加和频率计数[重复]

python 显示Pandas(Python)中每个值的频率

在 Python Pandas 中聚合组并从某个计数中吐出百分比

在 Python Pandas 中聚合组并从某个计数中吐出百分比