按 10 分钟间隔对 pandas DataFrame 进行分组[重复]

Posted

技术标签:

【中文标题】按 10 分钟间隔对 pandas DataFrame 进行分组[重复]【英文标题】:Grouping pandas DataFrame by 10 minute intervals [duplicate] 【发布时间】:2019-04-10 21:03:15 【问题描述】:

给定以下 pandas 数据框:

            timestamp
0     2018-10-05 23:07:02
1     2018-10-05 23:07:13
2     2018-10-05 23:07:23
3     2018-10-05 23:07:36
4     2018-10-05 23:08:02
5     2018-10-05 23:09:16
6     2018-10-05 23:09:21
7     2018-10-05 23:09:39
8     2018-10-05 23:09:47
9     2018-10-05 23:10:01
10    2018-10-05 23:10:11
11    2018-10-05 23:10:23
12    2018-10-05 23:10:59
13    2018-10-05 23:11:03
14    2018-10-08 03:35:32
15    2018-10-08 03:35:58
16    2018-10-08 03:37:16
17    2018-10-08 03:38:04
18    2018-10-08 03:38:30
19    2018-10-08 03:38:36
20    2018-10-08 03:38:42
21    2018-10-08 03:38:52
22    2018-10-08 03:38:57
23    2018-10-08 03:39:10
24    2018-10-08 03:39:27
25    2018-10-08 03:40:47
26    2018-10-08 03:40:54
27    2018-10-08 03:41:02
28    2018-10-08 03:41:12
29    2018-10-08 03:41:32

如何以每行十分钟的时间段标记?例如:

            timestamp       10min_period
0     2018-10-05 23:07:02   period_1
2     2018-10-05 23:07:23   period_1
1     2018-10-05 23:07:13   period_1
2     2018-10-05 23:07:23   period_1
3     2018-10-05 23:07:36   period_1
4     2018-10-05 23:08:02   period_1
5     2018-10-05 23:09:16   period_1
6     2018-10-05 23:09:21   period_1
7     2018-10-05 23:09:39   period_1
8     2018-10-05 23:09:47   period_1
9     2018-10-05 23:10:01   period_1
10    2018-10-05 23:10:11   period_1
11    2018-10-05 23:10:23   period_1
12    2018-10-05 23:10:59   period_1
13    2018-10-05 23:11:03   period_1
14    2018-10-08 03:35:32   period_2
15    2018-10-08 03:35:58   period_2
16    2018-10-08 03:37:16   period_2
17    2018-10-08 03:38:04   period_2
18    2018-10-08 03:38:30   period_2
19    2018-10-08 03:38:36   period_2
20    2018-10-08 03:38:42   period_2
21    2018-10-08 03:38:52   period_2
22    2018-10-08 03:38:57   period_2
23    2018-10-08 03:39:10   period_2
24    2018-10-08 03:39:27   period_2
25    2018-10-08 03:40:47   period_2
26    2018-10-08 04:40:54   period_3
27    2018-10-08 04:41:02   period_3
28    2018-10-08 04:41:12   period_3
29    2018-10-08 04:41:32   period_3

正如您在上述预期输出中所见,每个 period_n 标签都是通过计算 10 分钟的时间段来创建的,当日期时间序列超过 10 分钟的阈值时,将创建一个新标签。我尝试使用dt.floor(10Min) 对象,但是,它不起作用,因为它不跟踪从哪里开始以及从哪里结束计算 10 分钟的周期。我也尝试过:

a = df['timestamp'].offsets.DateOffset(minutes=10)

但是,它不起作用。知道如何在 10 分钟内分割我的 DF 吗?这个问题与其他问题不同,因为我没有指定任何特定的时间开始计算。也就是说,我从第一个 datetime 行实例开始计数,然后开始计数十个时间分钟的周期。

更新:

转化为datetime对象后,我也尝试过

df['timestamp'].groupby(pd.TimeGrouper(freq='10Min'))

但是,我得到了:

TypeError: Only valid with DatetimeIndex, TimedeltaIndex or PeriodIndex, but got an instance of 'RangeIndex'

【问题讨论】:

请看你接受的答案,它甚至不正确。 【参考方案1】:
df['timestamp'] = pd.to_datetime(df['timestamp'])
diffs = df['timestamp'] - df['timestamp'].shift()
laps = diffs > pd.Timedelta('10 min')
periods = laps.cumsum().apply(lambda x: 'period_'.format(x+1))
df['10min_period'] = periods

【讨论】:

这个答案不正确,并且没有达到 OP 的预期。目标是以十分钟为间隔进行分组,而不是根据差异分配标签。【参考方案2】:

为了重现您的问题,我这样做:

index = pd.date_range(datetime.datetime.now().date() - datetime.timedelta(10), periods=100, freq='min')

这样我就有了这个DataFrame:

a = pd.DataFrame(index)
a
                     0
0  2018-10-28 00:00:00
1  2018-10-28 00:01:00
2  2018-10-28 00:02:00
3  2018-10-28 00:03:00
4  2018-10-28 00:04:00
5  2018-10-28 00:05:00
6  2018-10-28 00:06:00
7  2018-10-28 00:07:00
8  2018-10-28 00:08:00
9  2018-10-28 00:09:00
10 2018-10-28 00:10:00
                   ...
[100 rows x 1 columns]

然后,我这样做:

a['period'] = a.apply(lambda x: "perdio_%d"%(int(x[0].minute/10) + 1), axis=1)

我有这个解决方案:

                     0    period
0  2018-10-28 00:00:00  perdio_1
1  2018-10-28 00:01:00  perdio_1
2  2018-10-28 00:02:00  perdio_1
3  2018-10-28 00:03:00  perdio_1
4  2018-10-28 00:04:00  perdio_1
5  2018-10-28 00:05:00  perdio_1
6  2018-10-28 00:06:00  perdio_1
7  2018-10-28 00:07:00  perdio_1
8  2018-10-28 00:08:00  perdio_1
9  2018-10-28 00:09:00  perdio_1
10 2018-10-28 00:10:00  perdio_2
11 2018-10-28 00:11:00  perdio_2
12 2018-10-28 00:12:00  perdio_2
13 2018-10-28 00:13:00  perdio_2
14 2018-10-28 00:14:00  perdio_2
15 2018-10-28 00:15:00  perdio_2
                             ...

希望对你有帮助

【讨论】:

【参考方案3】:

通过一点矢量化算法,这应该是可能的(并且是高性能的):

# Convert to datetime if not already.
# df['timestamp'] = pd.to_datetime(df['timestamp'], errors='coerce')    
u = (df.assign(timestamp=df['timestamp'].dt.floor('20min'))
       .groupby(pd.Grouper(key='timestamp',freq='10min'))
       .ngroup())

df['10min_period'] = np.char.add('period_', (pd.factorize(u)[0] + 1).astype(str))

不幸的是,这里的缺点是,虽然这将为您的样本数据产生预期的输出,但没有简单的方法来处理 10 分钟的连续间隔(pd.Grouper 不会从您列中的第一个日期开始分组, 所以dt.floor('20min') 作为初始步骤是必要的——这会在不经意间将“period_i+1”中的一些或大多数行合并到“period_i”下)。

【讨论】:

感谢您的帮助,但是,如果您检查预期输出,则 period_2 从第 14 行而不是第 9 行开始。原因是期间从 23:07:02 开始,到 23:11 结束:03(不到 10 分钟) 检查@ghilas 答案,有没有其他方法可以通过分解获得相同的结果?我觉得这个更优雅 @anon Ghilas 的答案更不正确,因为它根据 10 分钟内的第一个差异增加计数,而不是每 10 分钟分组一次。不知道您为什么接受并使用它。 如果你从2018-10-05 23: 07: 02开始数到`2018-10-05 23:11:03`你可以看到大约5分钟过去了。如果您查看下一行,即2018-10-08 03: 35: 32,您会注意到有超过 10 分钟的跳跃,因此开始计算新的时间段。也就是说,从2018-10-08 03: 35: 322018-10-08 03: 40: 47,由于下一个位置 2018 -10-08 04:40:54` 超过了 10 分钟,因此将这些行分配到新期间 (period_2)。我认为 factorize 方法非常优雅......有没有办法用它来做? @anon Factorize 只是重新标记已标记的行。我提供了一个略有不同的替代方案(类似于其他答案,但性能更高)。【参考方案4】:

我已将您的数据框保存在记事本中,并将其命名为 timestamp.txt。在记事本中看起来像这样:

然后我写了这个简单的代码:

import pandas as pd

timestamp = pd.read_csv("C:\\...path_of_your_file...\\timestamp.txt")  # read file
timestamp['10_Minute_Period'] = 0  # add column and initilize it to zero
numb_groups = int((timestamp.shape[0])/10)  # calculate number of groups
groups = 1  # initialize number of groups to one

while groups <= numb_groups+1:
   for idx, _ in timestamp.iterrows():  # iterate over row indexes
       # check if current row is below the group and the value is equal to 0
       if idx < groups*10 and timestamp.at[idx,'10_Minute_Period'] == 0:
           # in this case, write corresponding Period
           timestamp.loc[idx,'10_Minute_Period'] = ('Period' + str(groups))
   groups += 1  # increment groups and check while condition

print(timestamp)  # print the final modified timestamp

希望对你有帮助!

【讨论】:

感谢您的帮助!

以上是关于按 10 分钟间隔对 pandas DataFrame 进行分组[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Python - 按时间间隔分组的时间加权平均 Pandas

按 15 分钟间隔对 mysql 查询进行分组

Pandas 时间序列:常规 10 分钟窗口内不规则间隔数据的分组和滚动平均值

pandas TimeGrouper 自定义频率时间范围

在 Oracle SQL 中按时间间隔聚合数据

Oracle SQL 组行计数按 10 分钟的时间间隔