pandas 将不规则时间标记的测量值转换为等间隔的时间加权平均值

pkln4tw6  于 2022-12-28  发布在  其他
关注(0)|答案(4)|浏览(127)

我有一系列带有时间戳且间隔不规则的测量值。这些系列中的值始终表示测量值的变化--即没有变化就没有新值。此类系列的一个简单示例如下:

23:00:00.100     10
23:00:01.200      8
23:00:01.600      0
23:00:06.300      4

我想得到的是一系列等间隔的时间加权平均值,对于给定的例子,我可能会以秒为单位来确定频率,从而得到如下结果:

23:00:01     NaN ( the first 100ms are missing )
23:00:02     5.2 ( 10*0.2 + 8*0.4 + 0*0.4 )
23:00:03       0
23:00:04       0
23:00:05       0
23:00:06     2.8 ( 0*0.3 + 4*0.7 )

我正在寻找一个能解决这个问题的Python库,对我来说,这似乎是一个标准的问题,但是到目前为止,我还没有在像panda这样的标准库中找到这样的功能。
该算法需要考虑两件事:

  • 时间加权平均
  • 当形成平均值时考虑当前间隔之前(并且甚至可能超前)的值

用Pandas

data.resample('S', fill_method='pad')          # forming a series of seconds

提供一个用户定义的聚合函数将允许形成时间加权平均值,但是由于忽略了间隔的开始,这个平均值也将是不正确的。更糟糕的是:用平均值填充该系列中的孔,在该示例中从上面导致第3、4和5秒的值为非零。

data = data.resample('L', fill_method='pad')   # forming a series of milliseconds
data.resample('S')

以一定的准确性完成了这一任务,但是--取决于准确性--非常昂贵。就我而言,太贵了。

mrfwxfqh

mrfwxfqh1#

您可以使用traces执行此操作。

from datetime import datetime
import traces

ts = traces.TimeSeries(data=[
    (datetime(2016, 9, 27, 23, 0, 0, 100000), 10),
    (datetime(2016, 9, 27, 23, 0, 1, 200000), 8),
    (datetime(2016, 9, 27, 23, 0, 1, 600000), 0),
    (datetime(2016, 9, 27, 23, 0, 6, 300000), 4),
])

regularized = ts.moving_average(
    start=datetime(2016, 9, 27, 23, 0, 1),
    sampling_period=1,
    placement='left',
)

结果是:

[(datetime(2016, 9, 27, 23, 0, 1), 5.2),
 (datetime(2016, 9, 27, 23, 0, 2), 0.0),
 (datetime(2016, 9, 27, 23, 0, 3), 0.0),
 (datetime(2016, 9, 27, 23, 0, 4), 0.0),
 (datetime(2016, 9, 27, 23, 0, 5), 0.0),
 (datetime(2016, 9, 27, 23, 0, 6), 2.8)]
8i9zcol2

8i9zcol22#

这里有一个解决方案,它可能需要一些调整,以满足您的要求。
将秒数添加到索引中并向前填充:

tees = pd.Index(datetime(2000, 1, 1, 23, 0, n) for n in xrange(8))
df2 = df1.reindex(df1.index + tees)
df2['value'] = df2.value.ffill()

In [14]: df2
Out[14]:
                            value
2000-01-01 23:00:00           NaN
2000-01-01 23:00:00.100000     10
2000-01-01 23:00:01            10
2000-01-01 23:00:01.200000      8
2000-01-01 23:00:01.600000      0
2000-01-01 23:00:02             0
2000-01-01 23:00:03             0
2000-01-01 23:00:04             0
2000-01-01 23:00:05             0
2000-01-01 23:00:06             0
2000-01-01 23:00:06.300000      4
2000-01-01 23:00:07             4

取下一个值的时间差(使用shift),并乘以(值 * 秒):

df3['difference'] = df3['index'].shift(-1) - df3['index']
df3['tot'] = df3.apply(lambda row: np.nan
                                   if row['difference'].seconds > 2  # a not very robust check for NaT
                                   else row['difference'].microseconds * row['value'] / 1000000,
                        axis=1)

In [17]: df3
Out[17]:
                        index  value      difference  tot
0         2000-01-01 23:00:00    NaN 00:00:00.100000  NaN
1  2000-01-01 23:00:00.100000     10 00:00:00.900000  9.0
2         2000-01-01 23:00:01     10 00:00:00.200000  2.0
3  2000-01-01 23:00:01.200000      8 00:00:00.400000  3.2
4  2000-01-01 23:00:01.600000      0 00:00:00.400000  0.0
5         2000-01-01 23:00:02      0        00:00:01  0.0
6         2000-01-01 23:00:03      0        00:00:01  0.0
7         2000-01-01 23:00:04      0        00:00:01  0.0
8         2000-01-01 23:00:05      0        00:00:01  0.0
9         2000-01-01 23:00:06      0 00:00:00.300000  0.0
10 2000-01-01 23:00:06.300000      4 00:00:00.700000  2.8
11        2000-01-01 23:00:07      4             NaT  NaN

然后重新采样到秒(将值 * 秒相加):

In [18]: df3.set_index('index')['tot'].resample('S', how='sum')
Out[18]:
index
2000-01-01 23:00:00    9.0
2000-01-01 23:00:01    5.2
2000-01-01 23:00:02    0.0
2000-01-01 23:00:03    0.0
2000-01-01 23:00:04    0.0
2000-01-01 23:00:05    0.0
2000-01-01 23:00:06    2.8
2000-01-01 23:00:07    NaN
Freq: S, dtype: float64
  • 注意:终点需要一些强制(求和是聪明的,忽略了NaN)...*
bbmckpt7

bbmckpt73#

这不是一个答案,但我需要一些图表来确定时间加权平均值是多少。下面是一个用数据绘制的图表:

是否需要每个垂直跨度的平均值?第一个跨度为0-1,因为它包含未知数据,所以结果为NaN。第二个块为1-2,该值的计算方法为:(100.2 + 80.4 + 0*0.4)和你的一样,但我不知道5-6的价值是怎么来的:

23:00:06     2.8 ( 0*0.3 + 2*0.7 )

你能解释一下这个值是怎么计算出来的吗?

ldfqzlk8

ldfqzlk84#

import pandas as pa
import numpy as np
from datetime import datetime
from datetime import timedelta

time_stamps=[datetime(2013,04,11,23,00,00,100000), 
             datetime(2013,04,11,23,00,1,200000),
             datetime(2013,04,11,23,00,1,600000),
             datetime(2013,04,11,23,00,6,300000)]
values = [10, 8, 0, 4]
raw = pa.TimeSeries(index=time_stamps, data=values)

def round_down_to_second(dt):
    return datetime(year=dt.year, month=dt.month, day=dt.day, 
                    hour=dt.hour, minute=dt.minute, second=dt.second)

def round_up_to_second(dt):
    return round_down_to_second(dt) + timedelta(seconds=1)

def time_weighted_average(data):
    end = pa.DatetimeIndex([round_up_to_second(data.index[-1])])
    return np.average(data, weights=np.diff(data.index.append(end).asi8))

start = round_down_to_second(time_stamps[0])
end = round_down_to_second(time_stamps[-1])
range = pa.date_range(start, end, freq='S')
data = raw.reindex(raw.index + range)
data = data.ffill()

data = data.resample('S', how=time_weighted_average)

此答案以edit的形式发布在CC BY-SA 3.0下,通过OP Tim Tröndle将不规则时间戳测量值转换为等间隔的时间加权平均值。

相关问题