pandas.Grouper 时间间隔行为
pandas.Grouper for time intervals behavior
具有 ID 和时间戳的 DF,例如:
id timestamp idx
0 1 2021-10-24 17:56:03.641 0
1 1 2021-10-24 17:56:04.086 1
2 1 2021-10-24 17:56:11.217 2
我正在尝试按 5 分钟对每个 id 中的时间范围进行分组,并将每个组的第一个 idx 设置为整个范围,如下所示:
id timestamp idx first_index
0 1 2021-10-24 17:56:03.641 0 0
1 1 2021-10-24 17:56:04.086 1 0
2 1 2021-10-24 17:56:11.217 2 0
3 1 2021-10-24 19:33:50.359 3 3 <-- taking new idx out 5 min range
4 1 2021-10-24 19:33:55.278 4 3
我写了下面的代码:
def time_groups(df):
df = df.copy()
# grouping per 5Min and id
g = df.groupby(['id', pd.Grouper(key="timestamp", freq='5min', origin='start')])
# get first values per groups to new column
df['first_index'] = g['idx'].transform('first')
return df
代码对单个 id 工作正常,但是当我有一些 id 时,它会为相同的 id 产生不同的结果。我已经写了 following Colab 来重现这个问题。
所有数据 在 5 分钟前结束:
id timestamp idx first_index
171 6 2021-10-24 18:03:39.323 171 171
172 6 2021-10-24 18:03:53.551 172 171
173 6 2021-10-24 18:04:21.932 173 171
174 6 2021-10-24 18:04:22.221 174 171
175 6 2021-10-24 18:04:22.484 175 171
176 6 2021-10-24 18:04:36.399 176 171
177 6 2021-10-24 18:04:36.649 177 171
------------------------------------------------- Group end
178 6 2021-10-24 18:06:20.437 178 178
179 6 2021-10-24 18:06:20.695 179 178
180 6 2021-10-24 18:06:21.001 180 178
只有一个id 5分钟前不结束:
id timestamp idx first_index
171 6 2021-10-24 18:03:39.323 171 171
172 6 2021-10-24 18:03:53.551 172 171
173 6 2021-10-24 18:04:21.932 173 171
174 6 2021-10-24 18:04:22.221 174 171
175 6 2021-10-24 18:04:22.484 175 171
176 6 2021-10-24 18:04:36.399 176 171
177 6 2021-10-24 18:04:36.649 177 171
178 6 2021-10-24 18:06:20.437 178 171
179 6 2021-10-24 18:06:20.695 179 171
180 6 2021-10-24 18:06:21.001 180 171
我错过了什么?
更新:
如果去掉第一个ID:
df = df[3:]
代码工作正常
我认为这是因为 group[er origin 正在查看整个系列中的第一个时间戳,而不是每个分组的 id。
这似乎有效:
def tgs(df):
df_list = [g for _,g in df.groupby('id')]
res_list = []
for df_s in df_list:
g = df_s.groupby([pd.Grouper(key="timestamp", freq='5min', origin='start')])
df_s['first_index'] = g['idx'].transform('first')
res_list.append(df_s)
return pd.concat(res_list)
申请时:
df.groupby(['id', pd.Grouper(key="timestamp", freq='5min', origin='start')])
timestamp
分组的 origin
是整个数据帧中的第一个时间戳,而不是每个组。
根据文档 ‘start’: origin is the first value of the timeseries
https://pandas.pydata.org/docs/reference/api/pandas.Grouper.html
查看 df.groupby(['id', pd.Grouper(key="timestamp", freq='5min', origin='start')]).size()
,您可以看到所有组都以 5 分钟为间隔(或 5 分钟间隔的乘积),甚至是每个不同的组 id
:
id timestamp
1 2021-10-24 17:56:03.641 3
2 2021-10-24 19:31:03.641 10
2021-10-24 19:36:03.641 9
...
6 2021-10-24 18:01:03.641 7
2021-10-24 18:06:03.641 13
...
如果您查看 id
6,它的第一组实际上处于比它的第一个事件更早的时间戳。这是出于同样的原因——所有用户的“桶”都是基于从整个数据集的第一个时间戳开始的 5 分钟间隔。 18:06:03.641
之前的所有行都分组在 18:01:03.641
“桶”中,之后的所有行都分组到 18:06:03.641
“桶”。
数据集的第一行是最早的,因此当您删除第一个用户时,错误不再可见。
我认为您可以获得所需的功能,方法是先按 id
分组,然后使用 apply:
应用额外的 group-with-grouper
def split_to_five_minute_groups(x):
return (x.groupby([pd.Grouper(key="timestamp", freq='5min', origin='start')]))[['idx']].transform('first')
df['first_idx'] = df.groupby(['id']).apply(split_to_five_minute_groups)
具有 ID 和时间戳的 DF,例如:
id timestamp idx
0 1 2021-10-24 17:56:03.641 0
1 1 2021-10-24 17:56:04.086 1
2 1 2021-10-24 17:56:11.217 2
我正在尝试按 5 分钟对每个 id 中的时间范围进行分组,并将每个组的第一个 idx 设置为整个范围,如下所示:
id timestamp idx first_index
0 1 2021-10-24 17:56:03.641 0 0
1 1 2021-10-24 17:56:04.086 1 0
2 1 2021-10-24 17:56:11.217 2 0
3 1 2021-10-24 19:33:50.359 3 3 <-- taking new idx out 5 min range
4 1 2021-10-24 19:33:55.278 4 3
我写了下面的代码:
def time_groups(df):
df = df.copy()
# grouping per 5Min and id
g = df.groupby(['id', pd.Grouper(key="timestamp", freq='5min', origin='start')])
# get first values per groups to new column
df['first_index'] = g['idx'].transform('first')
return df
代码对单个 id 工作正常,但是当我有一些 id 时,它会为相同的 id 产生不同的结果。我已经写了 following Colab 来重现这个问题。
所有数据 在 5 分钟前结束:
id timestamp idx first_index
171 6 2021-10-24 18:03:39.323 171 171
172 6 2021-10-24 18:03:53.551 172 171
173 6 2021-10-24 18:04:21.932 173 171
174 6 2021-10-24 18:04:22.221 174 171
175 6 2021-10-24 18:04:22.484 175 171
176 6 2021-10-24 18:04:36.399 176 171
177 6 2021-10-24 18:04:36.649 177 171
------------------------------------------------- Group end
178 6 2021-10-24 18:06:20.437 178 178
179 6 2021-10-24 18:06:20.695 179 178
180 6 2021-10-24 18:06:21.001 180 178
只有一个id 5分钟前不结束:
id timestamp idx first_index
171 6 2021-10-24 18:03:39.323 171 171
172 6 2021-10-24 18:03:53.551 172 171
173 6 2021-10-24 18:04:21.932 173 171
174 6 2021-10-24 18:04:22.221 174 171
175 6 2021-10-24 18:04:22.484 175 171
176 6 2021-10-24 18:04:36.399 176 171
177 6 2021-10-24 18:04:36.649 177 171
178 6 2021-10-24 18:06:20.437 178 171
179 6 2021-10-24 18:06:20.695 179 171
180 6 2021-10-24 18:06:21.001 180 171
我错过了什么?
更新: 如果去掉第一个ID:
df = df[3:]
代码工作正常
我认为这是因为 group[er origin 正在查看整个系列中的第一个时间戳,而不是每个分组的 id。
这似乎有效:
def tgs(df):
df_list = [g for _,g in df.groupby('id')]
res_list = []
for df_s in df_list:
g = df_s.groupby([pd.Grouper(key="timestamp", freq='5min', origin='start')])
df_s['first_index'] = g['idx'].transform('first')
res_list.append(df_s)
return pd.concat(res_list)
申请时:
df.groupby(['id', pd.Grouper(key="timestamp", freq='5min', origin='start')])
timestamp
分组的 origin
是整个数据帧中的第一个时间戳,而不是每个组。
根据文档 ‘start’: origin is the first value of the timeseries
https://pandas.pydata.org/docs/reference/api/pandas.Grouper.html
查看 df.groupby(['id', pd.Grouper(key="timestamp", freq='5min', origin='start')]).size()
,您可以看到所有组都以 5 分钟为间隔(或 5 分钟间隔的乘积),甚至是每个不同的组 id
:
id timestamp
1 2021-10-24 17:56:03.641 3
2 2021-10-24 19:31:03.641 10
2021-10-24 19:36:03.641 9
...
6 2021-10-24 18:01:03.641 7
2021-10-24 18:06:03.641 13
...
如果您查看 id
6,它的第一组实际上处于比它的第一个事件更早的时间戳。这是出于同样的原因——所有用户的“桶”都是基于从整个数据集的第一个时间戳开始的 5 分钟间隔。 18:06:03.641
之前的所有行都分组在 18:01:03.641
“桶”中,之后的所有行都分组到 18:06:03.641
“桶”。
数据集的第一行是最早的,因此当您删除第一个用户时,错误不再可见。
我认为您可以获得所需的功能,方法是先按 id
分组,然后使用 apply:
def split_to_five_minute_groups(x):
return (x.groupby([pd.Grouper(key="timestamp", freq='5min', origin='start')]))[['idx']].transform('first')
df['first_idx'] = df.groupby(['id']).apply(split_to_five_minute_groups)