Усреднение значений с нерегулярными временными интервалами - PullRequest
1 голос
/ 17 июня 2020

У меня есть несколько пар массивов измерений и время, в которое были сделаны измерения, которые я хочу усреднить. К сожалению, время, в которое эти измерения проводились, не является регулярным или одинаковым для каждой пары.

Моя идея для их усреднения состоит в том, чтобы создать новый массив со значениями в каждую секунду, а затем усреднить их. Это работает, но кажется немного неуклюжим и означает, что мне нужно создавать много излишне длинных массивов.

Примеры входных данных

m1 = [0.4, 0.6, 0.2]
t1 = [0.0, 2.4, 5.2]

m2 = [1.0, 1.4, 1.0]
t2 = [0.0, 3.6, 4.8]

Сгенерированные регулярные массивы для значений каждую секунду

r1 = [0.4, 0.4, 0.4, 0.6, 0.6, 0.6, 0.2]
r2 = [1.0, 1.0, 1.0, 1.0, 1.4, 1.0]

Средние значения до длины самого короткого массива

a = [0.7, 0.7, 0.7, 0.8, 1.0, 0.8]

Моя попытка с учетом списка массивов измерений measurements и соответствующего списка массивов временных интервалов times

def granulate(values, times):
    count = 0
    regular_values = []
    for index, x in enumerate(times):
        while count <= x:
            regular_values.append(values[index])
            count += 1
    return np.array(regular_values)

processed_measurements = [granulate(m, t) for m, t in zip(measurements, times)]
min_length = min(len(m) for m in processed_measurements )
processed_measurements = [m[:min_length] for m in processed_measurements]
average_measurement = np.mean(processed_measurements, axis=0)

Is есть ли лучший способ сделать это, в идеале используя функции numpy?

Ответы [ 3 ]

1 голос
/ 17 июня 2020

Можно (немного больше numpy -i sh решение):

import numpy as np

# oddly enough - numpy doesn't have it's own ffill function:

def np_ffill(arr):
    mask = np.arange(len(arr))
    mask[np.isnan(arr)]=0
    np.maximum.accumulate(mask, axis=0, out=mask)
    return arr[mask]


t1=np.ceil(t1).astype("int")
t2=np.ceil(t2).astype("int")
r1=np.empty(max(t1)+1)
r2=np.empty(max(t2)+1)
r1[:]=np.nan
r2[:]=np.nan
r1[t1]=m1
r2[t2]=m2

r1=np_ffill(r1)
r2=np_ffill(r2)

>>> print(r1,r2)

[0.4 0.4 0.4 0.6 0.6 0.6 0.2] [1.  1.  1.  1.  1.4 1. ]

#in order to get avg:

r3=np.vstack([r1[:len(r2)],r2[:len(r1)]]).mean(axis=0)

>>> print(r3)
[0.7 0.7 0.7 0.8 1.  0.8]
1 голос
/ 17 июня 2020

Это будет среднее значение до ближайшей секунды:

time_series = np.arange(np.stack((t1, t2)).max())
np.mean([m1[abs(t1-time_series[:,None]).argmin(axis=1)], m2[abs(t2-time_series[:,None]).argmin(axis=1)]], axis=0)

Если вы хотите указать время до каждой секунды (с возможностью обобщения для большего количества массивов):

m = [m1, m2]
t = [t1, t2]
m_t=[]
time_series = np.arange(np.stack(t).max())
for i in range(len(t)):
  time_diff = time_series-t[i][:,None]
  m_t.append(m[i][np.where(time_diff > 0, time_diff, np.inf).argmin(axis=0)])
average = np.mean(m_t, axis=0)

вывод:

[0.7 0.7 0.7 0.8 1.  0.8]
0 голосов
/ 17 июня 2020

Я вижу два возможных решения:

  1. Создайте «ведро» для каждого временного шага, скажем, 1 секунду, и вставьте все измерения, которые были сделаны на временном шаге +/- 1 секунда в ведро. Усреднить все значения в сегменте.
  2. Интерполируйте каждую строку измерений, чтобы они имели равные временные шаги. Усреднить все измерения для каждого временного шага
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...