计算在 groupby 对象上经过的时间
Calculating time elapsed on a groupby object
我有一些时间序列数据,我想按类别分离出来,并在二进制值 == 1 时进一步分离。我想计算二进制值 == 1 时每天经过的时间。
原始数据样本如下:
category binary
utctime
2014-10-23 13:15:08 a 0
2014-10-24 16:09:13 b 0
2014-10-24 18:56:01 a 1
2014-10-24 21:42:42 a 1
2014-10-25 00:29:22 a 0
2014-10-25 03:16:02 c 1
2014-10-25 06:02:43 c 1
2014-10-25 08:49:23 c 0
2014-10-25 11:36:03 c 1
2014-10-25 14:22:43 c 1
2014-10-25 17:09:24 d 0
2014-10-25 19:56:05 b 0
2014-10-25 22:42:45 b 0
2014-10-26 01:29:26 e 0
2014-10-26 04:16:15 d 0
2014-10-26 07:02:56 e 1
2014-10-26 09:49:36 e 1
2014-10-26 12:36:16 e 0
2014-10-26 15:22:57 e 0
2014-10-26 18:09:46 d 0
2014-10-26 20:56:26 b 0
2014-10-26 23:43:07 e 0
我开始过滤二进制列,然后按类别分组,但我丢失了日期索引。如果我按 index.date(或 pd.date_grouper)分组,我不知道如何将子分组到单独的类别中。
感觉数据的形状可能特别无用,但我不知道如何让它变得更好 - 我尝试了一个以类别为列的数据透视表 table,但由于 utctimes 是唯一的到类别,那没有用。我应该从索引中取出 utctime 吗?
所需的输出类似于以下内容:
category a
date total time binary == 1
2014-10-23 10 minutes
2014-10-24 5 minutes
category b
date total time binary == 1
2014-10-23 1 minutes
2014-10-24 15 minutes
要按类别和索引日期分组,您可以使用
date = df2.index.date
grouped = df2.groupby(['category', date])
请注意,groupby 可以接受同时包含字符串和数组的列表。这
字符串指的是列名,而数组充当虚拟
柱子。 date
不是 df2
的列,但您可以按它们分组。很酷吧?
要查找每个组中的总分钟数,您可以使用 lambda 函数进行汇总,例如
lambda x: (x.index[-1]-x.index[0])/pd.Timedelta(1, 'm')
(x.index[-1]-x.index[0])
计算每组中第一个和最后一个时间戳之间的差异。请注意,这假定索引是按排序顺序排列的。
相差(x.index[-1]-x.index[0])
returns一个pd.Timedelta
。
除以 pd.Timedelta(1, 'm')
returns 总分钟数。
请注意,使用 g.last()-g.first()
的 对于大型 DataFrame 可能要快得多,因为它在一个向量化操作中计算所有 Timedelta,而不是使用一个 lambda 函数调用计算每个 Timedelta对于每一行。
import numpy as np
import pandas as pd
df = pd.DataFrame(
[['2014-10-23 13:15:08', 'a', 999.9, 0],
['2014-10-24 16:09:13', 'b', 24.1, 0],
['2014-10-24 18:56:01', 'a', 23.3, 1],
['2014-10-24 21:42:42', 'a', 23.0, 1],
['2014-10-25 00:29:22', 'a', 22.7, 0],
['2014-10-25 03:16:02', 'c', 23.1, 1],
['2014-10-25 06:02:43', 'c', 22.8, 1],
['2014-10-25 08:49:23', 'c', 23.7, 1],
['2014-10-25 11:36:03', 'c', 24.8, 0],
['2014-10-25 14:22:43', 'c', 25.7, 0],
['2014-10-25 17:09:24', 'd', 24.9, 0],
['2014-10-25 19:56:05', 'b', 24.6, 0],
['2014-10-25 22:42:45', 'b', 24.2, 0],
['2014-10-26 01:29:26', 'e', 22.7, 0],
['2014-10-26 04:16:15', 'd', 23.6, 0],
['2014-10-26 07:02:56', 'e', 22.4, 1],
['2014-10-26 09:49:36', 'e', 22.7, 1],
['2014-10-26 12:36:16', 'e', 22.2, 0],
['2014-10-26 15:22:57', 'e', 23.1, 0],
['2014-10-26 18:09:46', 'd', 23.8, 0],
['2014-10-26 20:56:26', 'b', 23.8, 0],
['2014-10-26 23:43:07', 'e', 22.7, 0]],
columns=['utctime', 'category', 'temp', 'binary'])
df = df.set_index('utctime')
df.index = pd.DatetimeIndex(df.index)
df2 = df.loc[df['binary']==1]
date = df2.index.date
grouped = df2.groupby(['category', date])
result = grouped['binary'].agg(
lambda x: (x.index[-1]-x.index[0])/pd.Timedelta(1, 'm'))
print(result)
产量
category
a 2014-10-24 166.683333
c 2014-10-25 333.350000
e 2014-10-26 166.666667
Name: binary, dtype: float64
使用@unutbu 数据和设置
添加一个我们也想比较的额外列
In [31]: df2['ts'] = df2.index
In [32]: df2
Out[32]:
category temp binary ts
2014-10-24 18:56:01 a 23.3 1 2014-10-24 18:56:01
2014-10-24 21:42:42 a 23.0 1 2014-10-24 21:42:42
2014-10-25 03:16:02 c 23.1 1 2014-10-25 03:16:02
2014-10-25 06:02:43 c 22.8 1 2014-10-25 06:02:43
2014-10-25 08:49:23 c 23.7 1 2014-10-25 08:49:23
2014-10-26 07:02:56 e 22.4 1 2014-10-26 07:02:56
2014-10-26 09:49:36 e 22.7 1 2014-10-26 09:49:36
一种更通用的分组方式
In [33]: g = df2.groupby(['category',pd.Grouper(freq='D',level=0)])
虽然是 YMMV,但性能会更高。
In [34]: g.last()-g.first()
Out[34]:
temp binary ts
category
a 2014-10-24 -0.3 0 02:46:41
c 2014-10-25 0.6 0 05:33:21
e 2014-10-26 0.3 0 02:46:40
In [35]: result = g.last()-g.first()
In [46]: result['ts'] = result['ts'] / Timedelta('1m')
In [47]: result
Out[47]:
temp binary ts
category
a 2014-10-24 -0.3 0 166.683333
c 2014-10-25 0.6 0 333.350000
e 2014-10-26 0.3 0 166.666667
我有一些时间序列数据,我想按类别分离出来,并在二进制值 == 1 时进一步分离。我想计算二进制值 == 1 时每天经过的时间。
原始数据样本如下:
category binary
utctime
2014-10-23 13:15:08 a 0
2014-10-24 16:09:13 b 0
2014-10-24 18:56:01 a 1
2014-10-24 21:42:42 a 1
2014-10-25 00:29:22 a 0
2014-10-25 03:16:02 c 1
2014-10-25 06:02:43 c 1
2014-10-25 08:49:23 c 0
2014-10-25 11:36:03 c 1
2014-10-25 14:22:43 c 1
2014-10-25 17:09:24 d 0
2014-10-25 19:56:05 b 0
2014-10-25 22:42:45 b 0
2014-10-26 01:29:26 e 0
2014-10-26 04:16:15 d 0
2014-10-26 07:02:56 e 1
2014-10-26 09:49:36 e 1
2014-10-26 12:36:16 e 0
2014-10-26 15:22:57 e 0
2014-10-26 18:09:46 d 0
2014-10-26 20:56:26 b 0
2014-10-26 23:43:07 e 0
我开始过滤二进制列,然后按类别分组,但我丢失了日期索引。如果我按 index.date(或 pd.date_grouper)分组,我不知道如何将子分组到单独的类别中。
感觉数据的形状可能特别无用,但我不知道如何让它变得更好 - 我尝试了一个以类别为列的数据透视表 table,但由于 utctimes 是唯一的到类别,那没有用。我应该从索引中取出 utctime 吗?
所需的输出类似于以下内容:
category a
date total time binary == 1
2014-10-23 10 minutes
2014-10-24 5 minutes
category b
date total time binary == 1
2014-10-23 1 minutes
2014-10-24 15 minutes
要按类别和索引日期分组,您可以使用
date = df2.index.date
grouped = df2.groupby(['category', date])
请注意,groupby 可以接受同时包含字符串和数组的列表。这
字符串指的是列名,而数组充当虚拟
柱子。 date
不是 df2
的列,但您可以按它们分组。很酷吧?
要查找每个组中的总分钟数,您可以使用 lambda 函数进行汇总,例如
lambda x: (x.index[-1]-x.index[0])/pd.Timedelta(1, 'm')
(x.index[-1]-x.index[0])
计算每组中第一个和最后一个时间戳之间的差异。请注意,这假定索引是按排序顺序排列的。
相差(x.index[-1]-x.index[0])
returns一个pd.Timedelta
。
除以 pd.Timedelta(1, 'm')
returns 总分钟数。
请注意,使用 g.last()-g.first()
的
import numpy as np
import pandas as pd
df = pd.DataFrame(
[['2014-10-23 13:15:08', 'a', 999.9, 0],
['2014-10-24 16:09:13', 'b', 24.1, 0],
['2014-10-24 18:56:01', 'a', 23.3, 1],
['2014-10-24 21:42:42', 'a', 23.0, 1],
['2014-10-25 00:29:22', 'a', 22.7, 0],
['2014-10-25 03:16:02', 'c', 23.1, 1],
['2014-10-25 06:02:43', 'c', 22.8, 1],
['2014-10-25 08:49:23', 'c', 23.7, 1],
['2014-10-25 11:36:03', 'c', 24.8, 0],
['2014-10-25 14:22:43', 'c', 25.7, 0],
['2014-10-25 17:09:24', 'd', 24.9, 0],
['2014-10-25 19:56:05', 'b', 24.6, 0],
['2014-10-25 22:42:45', 'b', 24.2, 0],
['2014-10-26 01:29:26', 'e', 22.7, 0],
['2014-10-26 04:16:15', 'd', 23.6, 0],
['2014-10-26 07:02:56', 'e', 22.4, 1],
['2014-10-26 09:49:36', 'e', 22.7, 1],
['2014-10-26 12:36:16', 'e', 22.2, 0],
['2014-10-26 15:22:57', 'e', 23.1, 0],
['2014-10-26 18:09:46', 'd', 23.8, 0],
['2014-10-26 20:56:26', 'b', 23.8, 0],
['2014-10-26 23:43:07', 'e', 22.7, 0]],
columns=['utctime', 'category', 'temp', 'binary'])
df = df.set_index('utctime')
df.index = pd.DatetimeIndex(df.index)
df2 = df.loc[df['binary']==1]
date = df2.index.date
grouped = df2.groupby(['category', date])
result = grouped['binary'].agg(
lambda x: (x.index[-1]-x.index[0])/pd.Timedelta(1, 'm'))
print(result)
产量
category
a 2014-10-24 166.683333
c 2014-10-25 333.350000
e 2014-10-26 166.666667
Name: binary, dtype: float64
使用@unutbu 数据和设置
添加一个我们也想比较的额外列
In [31]: df2['ts'] = df2.index
In [32]: df2
Out[32]:
category temp binary ts
2014-10-24 18:56:01 a 23.3 1 2014-10-24 18:56:01
2014-10-24 21:42:42 a 23.0 1 2014-10-24 21:42:42
2014-10-25 03:16:02 c 23.1 1 2014-10-25 03:16:02
2014-10-25 06:02:43 c 22.8 1 2014-10-25 06:02:43
2014-10-25 08:49:23 c 23.7 1 2014-10-25 08:49:23
2014-10-26 07:02:56 e 22.4 1 2014-10-26 07:02:56
2014-10-26 09:49:36 e 22.7 1 2014-10-26 09:49:36
一种更通用的分组方式
In [33]: g = df2.groupby(['category',pd.Grouper(freq='D',level=0)])
虽然是 YMMV,但性能会更高。
In [34]: g.last()-g.first()
Out[34]:
temp binary ts
category
a 2014-10-24 -0.3 0 02:46:41
c 2014-10-25 0.6 0 05:33:21
e 2014-10-26 0.3 0 02:46:40
In [35]: result = g.last()-g.first()
In [46]: result['ts'] = result['ts'] / Timedelta('1m')
In [47]: result
Out[47]:
temp binary ts
category
a 2014-10-24 -0.3 0 166.683333
c 2014-10-25 0.6 0 333.350000
e 2014-10-26 0.3 0 166.666667