使用 pandas 统计从开始时间起一小时内发生的用户订单,时间间隔不规则

Posted

技术标签:

【中文标题】使用 pandas 统计从开始时间起一小时内发生的用户订单,时间间隔不规则【英文标题】:Using pandas to count user orders that happen within the hour from start time with irregular time interval 【发布时间】:2020-10-03 17:51:46 【问题描述】:

假设我们有这个

| eventdatetime       | orderid | userid |
| 2019-12-27 03:06:50 | 1       |  100   |
| 2019-12-27 04:12:50 | 2       |  20    |
| 2019-12-27 05:06:58 | 3       |  140   |
| 2019-12-29 03:00:10 | 4       |  104   |

我尝试使用滚动 groupby,例如df.groupby('userid').rolling('1h').orderid.count() 但它不起作用,因为它向后看 1 小时并将其汇总到行中的当前日期时间。如果我使用滚动,它不期待在接下来的1小时内检查是否有订单。

例如如果查看 orderid 2,日期时间是 04:12:50,所以我想计算从这个时间到 05:12:50 的 1 小时内的订单数量。换句话说,计算用户从 04:12:50 到 05:12:50 下的订单数量 - 在这种情况下它是 2,但滚动会给我 1,因为它看起来是从 03:12:50 到 04:12:50。

pandas 中是否有任何功能可以做到这一点,还是我理解错误滚动?

编辑 1 最初我以为我可以只使用一些列,但不知何故它不适用于原始列,所以我将所有列都添加到混合中。

我们这里有日期时间索引和 3 个 id 列

                    | orderid           shopid      userid
event_time          
2019-12-31 13:13:34 | 31468414075366    214432425   1134243
2019-12-31 23:32:03 | 31505523761333    214432425   1134243
2019-12-31 23:45:49 | 31506349293329    214432425   52594422
2019-12-31 23:46:35 | 31506394434087    214432425   52594422

使用 Roy2012 的解决方案 但是添加了带有 orderid 的连接条件,因为我稍后需要 orderid 而不仅仅是时间

hour_ends = pd.DataFrame('hour_start': df.index, 
        'orderid': df.orderid.values
    , index=df.index + datetime.timedelta(hours=1)

t = pd.merge(df, hour_ends, on='orderid', left_index=True, right_index=True, how='outer')

给我

                     orderid            shopid        userid        event_start
event_time              
2019-12-31 13:13:34 | 31468414075366    214432425.0 | 1134243.0   | NaT
2019-12-31 14:13:34 | 31468414075366    NaN         | NaN         |2019-12-31 13:13:34
2019-12-31 23:32:03 | 31505523761333    214432425.0 | 1134243.0   | NaT
2019-12-31 23:45:49 | 31506349293329    214432425.0 | 52594422.0  | NaT
2019-12-31 23:46:35 | 31506394434087    214432425.0 | 52594422.0  | NaT
2020-01-01 00:32:03 | 31505523761333    NaN         | NaN         | 2019-12-31 23:32:03
2020-01-01 00:45:49 | 31506349293329    NaN         | NaN         | 2019-12-31 23:45:49
2020-01-01 00:46:35 | 31506394434087    NaN         | NaN         | 2019-12-31 23:46:35

然后添加它以向前滚动

t["rolling_count"] = t.rolling("1h", closed="both").count()["orderid"]
t.reset_index()[['event_start', 'orderid', 'rolling_count']].dropna()

给出这个不相符的结果

event_start         | orderid         | rolling_count
2019-12-31 13:13:34 | 31468414075366  | 2.0
2019-12-31 23:32:03 | 31505523761333  | 4.0
2019-12-31 23:45:49 | 31506349293329  | 4.0
2019-12-31 23:46:35 | 31506394434087  | 4.0

我希望结果是这样的

event_start         | orderid         | rolling_count
2019-12-31 13:13:34 | 31468414075366  | 1.0
2019-12-31 23:32:03 | 31505523761333  | 3.0
2019-12-31 23:45:49 | 31506349293329  | 2.0
2019-12-31 23:46:35 | 31506394434087  | 1.0

因为 orderid 31468414075366 从 13:13 1 小时内只有 1 个订单,31505523761333 从 23:32 到 00:32 1 小时内总共有 3 个订单,等等。

【问题讨论】:

df.rolling('1h')['userid'].count() 会给你结果,为什么要按用户 ID 分组? 好收获。我的意思是orderid计数。刚刚修好了。我正在计算用户在 1 小时内发出的订单。不计算用户。 【参考方案1】:

这里有一个解决方案。它基于在“真实”行之后一小时添加人工行的想法。我们将运行滚动计数,获取结果,然后将它们匹配回原始时间。这是代码,为了清楚起见,分为几个步骤。

import datetime

# Create a dataframe with 1 hour time windows
hour_ends = pd.DataFrame("hour_start":  df.index, 
                         index = df.index + datetime.timedelta(hours=1))

# merge the original dataframe and the new one. 
t = pd.merge(df, hour_ends, left_index=True, right_index=True, how = "outer")

# do the rolling count. 
t["rolling_count"] = t.rolling("1h", closed="both").count()["orderid"]

# match the results back to the starting time. 
res = t.reset_index()[["hour_start", "rolling_count"]].dropna()
print (res)

结果是:

           hour_start  rolling_count
1 2019-12-27 03:06:50            1.0
4 2019-12-27 04:12:50            2.0
5 2019-12-27 05:06:58            1.0
7 2019-12-29 03:00:10            1.0

【讨论】:

close="both" 是什么意思?有必要吗? 表示区间两边都是闭合的。它是必需的 - 否则它不会计算在该时间戳前一小时发生的 Ethel 事件。 它回答了你的问题吗?如果是这样,如果您能将其标记为后代的答案,那就太好了。 你知道为什么我不能反转我的 df 即 df.iloc[::-1] 并应用滚动吗? 有趣的想法。我的理解是索引是“要求单调的”——意思是,时间应该向前推进。无论如何,很高兴知道它是否回答了您的问题。

以上是关于使用 pandas 统计从开始时间起一小时内发生的用户订单,时间间隔不规则的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Pandas 数据框列中的日期时间减去 3 小时?

使用 pandas 时间序列在过去 n 小时内的变化率

pandas学习系列:时间序列

如何更改 seaborn 直方图以在一天中的几个小时内工作?

按 24 小时划分并使用 pyspark 或 panda 聚合

Pandas:如何分析带有开始和结束时间戳的数据?