我有一系列时间戳和不规则间距的测量。这些系列中的值总是代表测量值的变化 - 即没有变化就没有新值。这样一个系列的一个简单例子是:
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库。对我来说,这似乎是一个标准问题,但到目前为止我在像熊猫这样的标准库中找不到这样的功能。
算法需要考虑两件事:
data.resample('S', fill_method='pad') # forming a series of seconds
完成部分工作。为聚合提供用户定义的函数将允许to form time-weighted averages,但由于忽略了间隔的开始,因此该平均值也将是不正确的。更糟糕的是:系列中的孔用平均值填充,从上面的例子中导致秒3,4和5的值非零。
data = data.resample('L', fill_method='pad') # forming a series of milliseconds
data.resample('S')
具有一定的准确性,但是 - 取决于准确性 - 非常昂贵。就我而言,太贵了。
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)
答案 0 :(得分:4)
您可以使用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)]
答案 1 :(得分:3)
这不是答案,但我需要一些图表来确定什么是时间加权平均均值。以下是与您的数据一起绘制的图表:
您想要每个垂直跨度的平均值吗?第一个范围是0-1,因为它包含未知数据,结果是NaN。第二个块为1-2,该值的计算公式为:(10 * 0.2 + 8 * 0.4 + 0 * 0.4),与您的相同。但我不知道5-6的价值是如何出现的:
23:00:06 2.8 ( 0*0.3 + 2*0.7 )
你能解释一下如何计算这个值吗?
答案 2 :(得分:3)
这是一个解决方案,可能需要进行一些调整以满足您的要求。
将秒添加到索引并填充前方:
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)......