按 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: 32
到2018-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