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

Python 使用pandas统计从开始时间算起一小时内发生的用户订单,时间间隔不规则,python,pandas,time-series,rolling-computation,Python,Pandas,Time Series,Rolling Computation,假设我们有这个 | 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.group

假设我们有这个

| 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')。滚动('1h')。orderid.count()
,但它不起作用,因为它向后看了1个小时,并将其滚动到行中的当前日期时间。如果我使用滚动,它不期待在接下来的1小时内检查是否有订单

例如,如果查看orderid 2,则datetime为04:12:50,因此我想计算从该时间到05:12:50的1小时内的订单数量。换句话说,计算用户从04:12:50到05:12:50下的订单数量-在本例中是2,但滚动将得到1,因为它看起来是从03:12:50到04:12:50

熊猫身上有什么功能可以做到这一点,或者我对滚动理解有误吗

编辑1 起初我认为我可以只使用一些列,但不知怎么的,它不适用于原始列,所以我在混合中添加所有列

这里有datetime索引和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小时内只有一个订单,31505523761333在23:32到00:32的1小时内总共有3个订单,以此类推。

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

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

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

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

df.rolling('1h')['userid'].count()
会给你结果,为什么要在用户id上分组?很好。我是说orderid计数。刚刚解决了这个问题。我正在计算用户在1小时内的订单数量。不计算用户数。
df.rolling('1h')['userid'].count()
会给出结果,为什么要按用户id分组?很好。我是说orderid计数。刚刚解决了这个问题。我正在计算用户在1小时内的订单数量。不包括用户。closed=“tware”是什么意思?有必要吗?这意味着区间两边都是封闭的。它是必需的——或者它不会计算在时间戳前一小时发生的事件。它回答了你的问题吗?如果是这样的话,如果你能将它标记为后代的答案,那就太好了。你知道为什么我不能反转我的df,即df.iloc[::-1]并应用滚动吗?有趣的想法。我的理解是,索引“必须是单调的”——也就是说,时间应该向前推进。不管怎样,如果知道它是否回答了您的问题就好了。closed=“tware”是什么意思?有必要吗?这意味着区间两边都是封闭的。它是必需的——或者它不会计算在时间戳前一小时发生的事件。它回答了你的问题吗?如果是这样的话,如果你能将它标记为后代的答案,那就太好了。你知道为什么我不能反转我的df,即df.iloc[::-1]并应用滚动吗?有趣的想法。我的理解是,索引“必须是单调的”——也就是说,时间应该向前推进。不管怎样,如果它能回答你的问题,那就太好了。