Python:使用梯形规则快速计算平均值

时间:2018-04-10 16:12:19

标签: python python-3.x numpy scipy

使用Python,我必须处理一些数据。

我在大约1000万个时间点给出了大约50个函数的值。这些值以2D列表matrix的形式给出,即matrix[i]是值列表

[t_i, value of f1 at t_i, value of f2 at t_i ..., value of fN of t_i]

其中N = 50

由于

  • 数据中的可能噪声(功能是一些测量)
  • 非等距时间点(有时,时间步长为几秒,但有时可以用天测量)

我决定使用固定长度的某些预定义时间间隔内给定值的平均值。

我尝试了不同长度的间隔:它们的范围在1分钟到1小时之间。

我计算平均值的算法如下:

matrix = ...  # read matrix
t0 = matrix[0][0]
ts_new = [t0 + i * time_step for i in range(some_bound)]
buckets = [[] for t in ts_new]
for i, instance in enumerate(matrix):
    t_i = instance[0]
    put i to the bucket with index j, such that ts_new[j] <= t_i < ts_new[j + 1] 
for bucket in buckets:
    compute the average values of f1, ... , fN over the instances from bucket
  

算法的瓶颈是最后一个for循环。

如果我将matrix转换为numpy.array并将bucket的平均值计算为matrix[bucket, :].mean(axis=0),那么的效果非常快,但是计算值没有多大意义

如果f1的值ts = [0, 99, 100]分别为ys = [0, 0, 2],则均值函数返回2/3(如预期的那样)。但是,f1的平均值应该更接近0。使用梯形规则,可以获得0.01的平均值,这更有意义。

所以,目前,我正在使用

  • 用于计算铲斗平均值的scipy.integrate.trapz方法:梯形区域除以区间长度
  • 用于获取区间边界处的函数scipy.interpolate.interp1d的值的f方法,例如,我使用前一个存储桶中的最后一个点和给定存储桶中的第一个点来计算值在相应的时间间隔开始时(类似于时间间隔的结束)

需要第二个子弹,因为一个微小的时间间隔长度太短,以至于桶中有时只有1或2个点。程序如下:

# for one bucket
means = [0 for col in range(N)]
for col in range(1, N + 1):  # for each function f
    xs = []
    ys = []
    if can_interpolate_at_start:
        f_lin = scipy.interpolate.interp1d([tPrevLast, tNowFirst], [yPrevLast, yNowFirst])
        xs.append(t_bucketStart)
        ys.append(f_lin(t_bucketStart))
    xs += matrix[bucket, 0]
    ys += matrix[bucket, col]
    if can_interpolate_at_end:
        # ...
    means[col - 1] = scipy.integrate.trapz(ys, xs) / (xs[-1] - xs[0])

can_interpolate_at_startcan_interpolate_at_end的值仅取决于时间间隔(但必须特别注意第一个和最后一个桶......):如果是,我不使用插值点例如,前一个存储桶中的最后一个点与当前存储桶之间的时间差太大。

  

我的问题:当前的方法非常慢(一分钟时间间隔两小时左右)。我怎样才能让它更快?

1 个答案:

答案 0 :(得分:1)

你可以做的一件简单的事情是,根据间隔考虑每个区间的每个函数的平均值,然后乘以区间长度,然后除以总时间:

import numpy as np

matrix = ...
data = np.asarray(matrix)
t_diff = np.diff(data[:, 0])
means_sum = np.sum(t_diff[:, np.newaxis] * (data[:-1, 1:] + data[1:, 1:]) / 2, axis=0)
means = means_sum / (data[-1, 0] - data[0, 0])