在 python 中计算一小时内的不同操作
Count different actions within one hour in python
我开始使用时间序列。我有一个用户向不同的国家/地区进行银行转账,但是 he/she 进行转账的最频繁的国家/地区是 X,但也有向 Y 和 Z 国家/地区的转账。假设:
date id country
2020-01-01T00:00:00.000Z id_01 X
2020-01-01T00:20:00.000Z id_02 X
2020-01-01T00:25:00.000Z id_03 Y
2020-01-01T00:35:00.000Z id_04 X
2020-01-01T00:45:00.000Z id_05 Z
2020-01-01T01:00:00.000Z id_06 X
2020-01-01T10:20:00.000Z id_07 X
2020-01-01T10:25:00.000Z id_08 X
2020-01-01T13:00:00.000Z id_09 X
2020-01-01T18:45:00.000Z id_10 Z
2020-01-01T18:55:00.000Z id_11 X
由于最频繁出现的国家是 X,我想迭代地计算一小时内(在整个事件列表中)有多少笔交易是针对不同于 X 的国家完成的。
此特定案例的预期输出格式为:
date id country
2020-01-01T00:25:00.000Z id_03 Y
2020-01-01T00:45:00.000Z id_05 Z
从2020-01-01T00:00:00.000Z
开始,一小时内有两笔Y、Z交易。然后从2020-01-01T00:20:00.000Z
开始,一个小时内,有相同的交易,以此类推。那么,从2020-01-01T10:20:00.000Z
开始,一小时内,都是X。从2020-01-01T18:45:00.000Z
开始,一小时内,只有一个Z。
我正在尝试使用双重 for 循环和 .value_counts(),但我不确定自己在做什么。
你可以试试:
df['date'] = pd.to_datetime(df.date)
(df.country != 'X').groupby(by=df.date.dt.hour).sum()
首先,它将您的日期列转换为日期时间。然后,您测试国家/地区是否为 'X',并按小时分组,并对不同于 'X' 的国家/地区数量求和。组是基于小时,而不是滚动消逝的时间。希望它能解决您的问题!
IIUC,你可以 select 只有行不是 X,然后使用 diff
一次向前和一次向后(前后 1 小时内)并且你想要两个差异中的任何一个低于 1 小时的 Timedelta
。
#convert to datetime
df['date'] = pd.to_datetime(df['date'])
#mask not X and select only these rows
mX = df['country'].ne('X')
df_ = df[mX].copy()
# mask within an hour before and after
m1H = (df_['date'].diff().le(pd.Timedelta(hours=1)) |
df_['date'].diff(-1).le(pd.Timedelta(hours=1)) )
# selet only the rows meeting criteria on X and 1H
df_ = df_[m1H]
print (df_)
date id country
2 2020-01-01 00:25:00+00:00 id_03 Y
4 2020-01-01 00:45:00+00:00 id_05 Z
您是否考虑过为此使用时间序列数据库?如果您以任意时间间隔进行大量基于事件的聚合,它会让您的生活更轻松。时间序列数据库为您抽象了这一点,因此您只需发送一个查询并将结果输入 pandas。它也会 运行 相当快。
例如,可以在 QuestDB 中使用以下语法完成每小时聚合。
select timestamp, country, count() from yourTable SAMPLE BY 1h
这将 return 这样的结果
| timestamp | country | count |
| 2020-06-22T00:00:00 | X | 234 |
| 2020-06-22T00:00:00 | Y | 493 |
| 2020-06-22T01:00:00 | X | 12 |
| 2020-06-22T01:00:00 | Y | 66 |
您可以将其调整为每月或每周或 5 分钟的解决结果,而无需重新编写您的逻辑,您需要做的就是将 1h
更改为 1M
,7d
或 5m
或将其作为参数传递。
现在,要获得目标交易时间戳前后一小时的结果,您可以在上面添加时间戳间隔搜索。例如,假设您的目标交易发生在 2010-01-01T06:47:00.000000Z
,结果搜索将是
select hour, country, count() from yourTable
where timestamp = '2010-01-01T05:47:00.000000Z;2h'
sample by 1h;
如果这对您有用,有一个教程介绍如何在 QuestDB 中 运行 这种类型的查询并将结果输入 pandas here
我开始使用时间序列。我有一个用户向不同的国家/地区进行银行转账,但是 he/she 进行转账的最频繁的国家/地区是 X,但也有向 Y 和 Z 国家/地区的转账。假设:
date id country
2020-01-01T00:00:00.000Z id_01 X
2020-01-01T00:20:00.000Z id_02 X
2020-01-01T00:25:00.000Z id_03 Y
2020-01-01T00:35:00.000Z id_04 X
2020-01-01T00:45:00.000Z id_05 Z
2020-01-01T01:00:00.000Z id_06 X
2020-01-01T10:20:00.000Z id_07 X
2020-01-01T10:25:00.000Z id_08 X
2020-01-01T13:00:00.000Z id_09 X
2020-01-01T18:45:00.000Z id_10 Z
2020-01-01T18:55:00.000Z id_11 X
由于最频繁出现的国家是 X,我想迭代地计算一小时内(在整个事件列表中)有多少笔交易是针对不同于 X 的国家完成的。
此特定案例的预期输出格式为:
date id country
2020-01-01T00:25:00.000Z id_03 Y
2020-01-01T00:45:00.000Z id_05 Z
从2020-01-01T00:00:00.000Z
开始,一小时内有两笔Y、Z交易。然后从2020-01-01T00:20:00.000Z
开始,一个小时内,有相同的交易,以此类推。那么,从2020-01-01T10:20:00.000Z
开始,一小时内,都是X。从2020-01-01T18:45:00.000Z
开始,一小时内,只有一个Z。
我正在尝试使用双重 for 循环和 .value_counts(),但我不确定自己在做什么。
你可以试试:
df['date'] = pd.to_datetime(df.date)
(df.country != 'X').groupby(by=df.date.dt.hour).sum()
首先,它将您的日期列转换为日期时间。然后,您测试国家/地区是否为 'X',并按小时分组,并对不同于 'X' 的国家/地区数量求和。组是基于小时,而不是滚动消逝的时间。希望它能解决您的问题!
IIUC,你可以 select 只有行不是 X,然后使用 diff
一次向前和一次向后(前后 1 小时内)并且你想要两个差异中的任何一个低于 1 小时的 Timedelta
。
#convert to datetime
df['date'] = pd.to_datetime(df['date'])
#mask not X and select only these rows
mX = df['country'].ne('X')
df_ = df[mX].copy()
# mask within an hour before and after
m1H = (df_['date'].diff().le(pd.Timedelta(hours=1)) |
df_['date'].diff(-1).le(pd.Timedelta(hours=1)) )
# selet only the rows meeting criteria on X and 1H
df_ = df_[m1H]
print (df_)
date id country
2 2020-01-01 00:25:00+00:00 id_03 Y
4 2020-01-01 00:45:00+00:00 id_05 Z
您是否考虑过为此使用时间序列数据库?如果您以任意时间间隔进行大量基于事件的聚合,它会让您的生活更轻松。时间序列数据库为您抽象了这一点,因此您只需发送一个查询并将结果输入 pandas。它也会 运行 相当快。
例如,可以在 QuestDB 中使用以下语法完成每小时聚合。
select timestamp, country, count() from yourTable SAMPLE BY 1h
这将 return 这样的结果
| timestamp | country | count |
| 2020-06-22T00:00:00 | X | 234 |
| 2020-06-22T00:00:00 | Y | 493 |
| 2020-06-22T01:00:00 | X | 12 |
| 2020-06-22T01:00:00 | Y | 66 |
您可以将其调整为每月或每周或 5 分钟的解决结果,而无需重新编写您的逻辑,您需要做的就是将 1h
更改为 1M
,7d
或 5m
或将其作为参数传递。
现在,要获得目标交易时间戳前后一小时的结果,您可以在上面添加时间戳间隔搜索。例如,假设您的目标交易发生在 2010-01-01T06:47:00.000000Z
,结果搜索将是
select hour, country, count() from yourTable
where timestamp = '2010-01-01T05:47:00.000000Z;2h'
sample by 1h;
如果这对您有用,有一个教程介绍如何在 QuestDB 中 运行 这种类型的查询并将结果输入 pandas here