如何将(timestamp,value)数组转换为时间序列

时间:2013-12-30 21:03:25

标签: python numpy pandas scipy time-series

我有一个相当直接的问题,我希望以比我目前更高的效率解决这个问题。

我有一堆数据作为一组监控指标进入。输入数据结构为元组数组。每个元组都是(时间戳,值)。时间戳是整数纪元秒,值是正常浮点数。示例:

inArr = [ (1388435242, 12.3), (1388435262, 11.1), (1388435281, 12.8), ... ]

时间戳并不总是相同的秒数,但它通常是接近的。有时我们会提交重复的数字,有时我们会错过数据点等。

我当前的解决方案采用时间戳和:

  • 查找每对连续时间戳之间的num秒;
  • 找到这些延迟的中位数;
  • 创建一个正确大小的数组;
  • 假设第一个时间段从第一个时间戳之前的中间值的一半开始(将测量值放在时间段的中间);
  • 对碰巧进入同一时间段的值进行平均值;
  • 根据正确的(timestamp - starttime)/ median元素向此数组添加数据。
  • 如果时间范围没有值,我显然会输出一个无值。

输出数据必须采用以下格式:

outArr = [ (startTime, timeStep, numVals), [ val1, val2, val3, val4, ... ] ]

我怀疑这是Python Pandas http://pandas.pydata.org/(或Numpy / SciPy)解决的问题。

是的,我的解决方案有效,但是当我在60K数据点上运行时,可能需要十分之一秒(或更长时间)才能运行。当我尝试处理大量数量的数据集时,这很麻烦。

所以,我正在寻找一种可能比我的纯Python版本运行得更快的解决方案。我想我(根据之前与Argonne国家实验室人员的几次谈话)假设SciPy和Numpy在阵列操作中“稍微快一点”。我在Pandas代码中看了一下(大约一个小时左右),但是做这组操作看起来很麻烦。我不对吗?

- 编辑以显示预期输出 -

数据点之间的中间时间是20秒,一半是10秒。为了确保我们在时间戳之间放置线条,我们将开始时间设置在第一个数据点之前10秒。如果我们只是将开始时间作为第一个时间戳,那么我们在一个时间间隔内获得2个时间戳的可能性要大得多。

所以,1388435242 - 10 = 1388435232.时间步长是中位数,20秒。这里的数字是3。

outArr = [ (1388435232, 20, 3), [ 12.3, 11.1, 12.8 ] )

这是Graphite在绘制输出图形时所期望的格式;这不是我的发明。但是,将时间序列数据放在这种格式中似乎很常见 - 开始时间,间隔,然后是数组数组。

2 个答案:

答案 0 :(得分:3)

这是草图

创建输入系列

In [24]: x = zip(pd.date_range('20130101',periods=1000000,freq='s').asi8/1000000000,np.random.randn(1000000))

In [49]: x[0]
Out[49]: (1356998400, 1.2809949462375376)

创建框架

In [25]: df = DataFrame(x,columns=['time','value'])

使日期有点随机(模拟一些数据)

In [26]: df['time1'] = df['time'] + np.random.randint(0,10,size=1000000)

将纪元秒转换为datetime64 [ns] dtype

In [29]: df['time2'] = pd.to_datetime(df['time1'],unit='s')

区分系列(创建timedeltas)

In [32]: df['diff'] = df['time2'].diff()

看起来像这样

In [50]: df
Out[50]: 
          time     value       time1               time2      diff
0   1356998400 -0.269644  1356998405 2013-01-01 00:00:05       NaT
1   1356998401 -0.924337  1356998401 2013-01-01 00:00:01 -00:00:04
2   1356998402  0.952466  1356998410 2013-01-01 00:00:10  00:00:09
3   1356998403  0.604783  1356998411 2013-01-01 00:00:11  00:00:01
4   1356998404  0.140927  1356998407 2013-01-01 00:00:07 -00:00:04
5   1356998405 -0.083861  1356998414 2013-01-01 00:00:14  00:00:07
6   1356998406  1.287110  1356998412 2013-01-01 00:00:12 -00:00:02
7   1356998407  0.539957  1356998414 2013-01-01 00:00:14  00:00:02
8   1356998408  0.337780  1356998412 2013-01-01 00:00:12 -00:00:02
9   1356998409 -0.368456  1356998410 2013-01-01 00:00:10 -00:00:02
10  1356998410 -0.355176  1356998414 2013-01-01 00:00:14  00:00:04
11  1356998411 -2.912447  1356998417 2013-01-01 00:00:17  00:00:03
12  1356998412 -0.003209  1356998418 2013-01-01 00:00:18  00:00:01
13  1356998413  0.122424  1356998414 2013-01-01 00:00:14 -00:00:04
14  1356998414  0.121545  1356998421 2013-01-01 00:00:21  00:00:07
15  1356998415 -0.838947  1356998417 2013-01-01 00:00:17 -00:00:04
16  1356998416  0.329681  1356998419 2013-01-01 00:00:19  00:00:02
17  1356998417 -1.071963  1356998418 2013-01-01 00:00:18 -00:00:01
18  1356998418  1.090762  1356998424 2013-01-01 00:00:24  00:00:06
19  1356998419  1.740093  1356998428 2013-01-01 00:00:28  00:00:04
20  1356998420  1.480837  1356998428 2013-01-01 00:00:28  00:00:00
21  1356998421  0.118806  1356998427 2013-01-01 00:00:27 -00:00:01
22  1356998422 -0.935749  1356998427 2013-01-01 00:00:27  00:00:00

计算中位数

In [34]: df['diff'].median()
Out[34]: 
0   00:00:01
dtype: timedelta64[ns]

计算平均值

In [35]: df['diff'].mean()
Out[35]: 
0   00:00:00.999996
dtype: timedelta64[ns]

应该让你入门

答案 1 :(得分:1)

您可以将inArr传递给pandas Dataframe:

df = pd.DataFrame(inArr, columns=['time', 'value'])
    每个连续的时间戳对之间的
  • num秒: df['time'].diff()
  • 延迟中位数df['time'].diff().median()
  • 创建一个大小正确的数组(我认为这是照顾的?)
  • 假设第一个时间段开始于第一个时间戳之前的中间值的一半(将测量值放在时间段的中间);我不知道你的意思
  • 对碰巧进入同一时间段的值进行平均值

对于其中的一些问题,可能会将您的秒数转换为datetime并将其设置为索引:

In [39]: df['time'] = pd.to_datetime(df['time'], unit='s')
In [41]: df = df.set_index('time')

In [42]: df
Out[42]: 
                     value
time                      
2013-12-30 20:27:22   12.3
2013-12-30 20:27:42   11.1
2013-12-30 20:28:01   12.8

然后要同时处理多个值,请使用groupby

In [49]: df.groupby(level='time').mean()
Out[49]: 
                     value
time                      
2013-12-30 20:27:22   12.3
2013-12-30 20:27:42   11.1
2013-12-30 20:28:01   12.8

这是相同的,因为没有任何欺骗。

不确定你对最后两个的意思。

你想要的输出似乎与你之前想要的相反。您应该对具有相同时间戳的值进行平均,现在您想要它们全部?也许清楚一点。