如何在pandas时间序列中基于5分钟间隔创建组ID?
我有一个时间序列的数据框 df
,它的样子是这样的(这些时间序列发生在同一天,但在不同的小时):
id val
time
2014-04-03 16:01:53 23 14389
2014-04-03 16:01:54 28 14391
2014-04-03 16:05:55 24 14393
2014-04-03 16:06:25 23 14395
2014-04-03 16:07:01 23 14395
2014-04-03 16:10:09 23 14395
2014-04-03 16:10:23 26 14397
2014-04-03 16:10:57 26 14397
2014-04-03 16:11:10 26 14397
我需要从 16:00:00
开始,每5分钟分成一组。也就是说,所有在 16:00:00
到 16:05:00
这个时间段内的行,它们的新列 period
的值是1。(每组的行数是不固定的,所以我不能简单地把组切开)
最终,数据应该看起来像这样:
id val period
time
2014-04-03 16:01:53 23 14389 1
2014-04-03 16:01:54 28 14391 1
2014-04-03 16:05:55 24 14393 2
2014-04-03 16:06:25 23 14395 2
2014-04-03 16:07:01 23 14395 2
2014-04-03 16:10:09 23 14395 3
2014-04-03 16:10:23 26 14397 3
2014-04-03 16:10:57 26 14397 3
2014-04-03 16:11:10 26 14397 3
这样做的目的是为了进行一些 groupby
操作,但我需要的操作不在 pd.resample(how=' ')
方法中。所以我必须创建一个 period
列来标识每一组,然后用 df.groupby('period').apply(myfunc)
来处理。
任何帮助或意见都非常感谢。
谢谢!
2 个回答
1
根据你在做什么,如果我理解你的问题没错,其实可以通过使用重采样的方法来更简单地完成。
#Get some data
index = pd.DatetimeIndex(start='2013-01-01 00:00', end='2013-01-31 00:00', freq='min')
a = np.random.randint(20, high=30, size=(len(index),1))
b = np.random.randint(14440, high=14449, size=(len(index),1))
df = pd.DataFrame(np.concatenate((a,b), axis=1), index=index, columns=['id','val'])
df.head()
Out[34]:
id val
2013-01-01 00:00:00 20 14446
2013-01-01 00:01:00 25 14443
2013-01-01 00:02:00 25 14448
2013-01-01 00:03:00 20 14445
2013-01-01 00:04:00 28 14442
#Define function for variance
import numpy as np
def pyfun(X):
if X.shape[0] <= 1:
result = nan
else:
total = 0
for x in X:
total = total + x
mean = float(total) / X.shape[0]
total = 0
for x in X:
total = total + (mean-x)**2
result = float(total) / (X.shape[0]-1)
return result
#Try it out
df.resample('5min', how=pyfun)
Out[53]:
id val
2013-01-01 00:00:00 12.3 5.7
2013-01-01 00:05:00 9.3 7.3
2013-01-01 00:10:00 4.7 0.8
2013-01-01 00:15:00 10.8 10.3
2013-01-01 00:20:00 11.5 1.5
这真是太简单了。这是针对你自己定义的函数,不过如果你想用一个库里的函数,那你只需要在“how”这个关键词里指定这个函数就可以了。
df.resample('5min', how=np.var).head()
Out[54]:
id val
2013-01-01 00:00:00 12.3 5.7
2013-01-01 00:05:00 9.3 7.3
2013-01-01 00:10:00 4.7 0.8
2013-01-01 00:15:00 10.8 10.3
2013-01-01 00:20:00 11.5 1.5
19
你可以在 groupy/apply
中使用 TimeGrouper
函数。有了 TimeGrouper
,你就不需要自己创建时间段的列。我知道你并不是想计算平均值,但我会用这个作为例子:
>>> df.groupby(pd.TimeGrouper('5Min'))['val'].mean()
time
2014-04-03 16:00:00 14390.000000
2014-04-03 16:05:00 14394.333333
2014-04-03 16:10:00 14396.500000
或者用一个明确的 apply
示例:
>>> df.groupby(pd.TimeGrouper('5Min'))['val'].apply(lambda x: len(x) > 3)
time
2014-04-03 16:00:00 False
2014-04-03 16:05:00 False
2014-04-03 16:10:00 True
TimeGrouper
的文档说明:
Docstring for resample:class TimeGrouper@21
TimeGrouper(self, freq = 'Min', closed = None, label = None,
how = 'mean', nperiods = None, axis = 0, fill_method = None,
limit = None, loffset = None, kind = None, convention = None, base = 0,
**kwargs)
Custom groupby class for time-interval grouping
Parameters
----------
freq : pandas date offset or offset alias for identifying bin edges
closed : closed end of interval; left or right
label : interval boundary to use for labeling; left or right
nperiods : optional, integer
convention : {'start', 'end', 'e', 's'}
If axis is PeriodIndex
Notes
-----
Use begin, end, nperiods to generate intervals that cannot be derived
directly from the associated object
编辑
我不知道有没有简单的方法来创建时间段列,但下面的方法是可以的:
>>> new = df.groupby(pd.TimeGrouper('5Min'),as_index=False).apply(lambda x: x['val'])
>>> df['period'] = new.index.get_level_values(0)
>>> df
id val period
time
2014-04-03 16:01:53 23 14389 0
2014-04-03 16:01:54 28 14391 0
2014-04-03 16:05:55 24 14393 1
2014-04-03 16:06:25 23 14395 1
2014-04-03 16:07:01 23 14395 1
2014-04-03 16:10:09 23 14395 2
2014-04-03 16:10:23 26 14397 2
2014-04-03 16:10:57 26 14397 2
2014-04-03 16:11:10 26 14397 2
这个方法有效是因为这里的 groupby 设置为 as_index=False,实际上返回了你想要的时间段列,作为多重索引的一部分。我只是抓取了多重索引中的那部分,并把它分配给原始数据框中的新列。在 apply 中你可以做任何事情,我只是想要索引:
>>> new
time
0 2014-04-03 16:01:53 14389
2014-04-03 16:01:54 14391
1 2014-04-03 16:05:55 14393
2014-04-03 16:06:25 14395
2014-04-03 16:07:01 14395
2 2014-04-03 16:10:09 14395
2014-04-03 16:10:23 14397
2014-04-03 16:10:57 14397
2014-04-03 16:11:10 14397
>>> new.index.get_level_values(0)
Int64Index([0, 0, 1, 1, 1, 2, 2, 2, 2], dtype='int64')