Создание равномерно дискретизированного массива из неравномерно дискретизированных данных в NumPy

проблема в том, что я хочу уменьшить объем данных для графиков и анализа. Я использую Python и Numpy. Выборка данных неравномерна, поэтому существует массив временных меток и массив соответствующих значений. Я хочу, чтобы между точками данных было хотя бы определенное время. У меня есть простое решение, написанное на Python, где индексы находятся там, где есть хотя бы одна секунда между образцами:

import numpy as np

t = np.array([0, 0.1, 0.2, 0.3, 1.0, 2.0, 4.0, 4.1, 4.3, 5.0 ]) # seconds
v = np.array([0, 0.0, 2.0, 2.0, 2.0, 4.0, 4.0, 5.0, 5.0, 5.0 ])

idx = [0]
last_t = t[0]
min_dif = 1.0 # Minimum distance between samples in time
for i in range(1, len(t)):
    if last_t + min_dif <= t[i]:
        last_t = t[i]
        idx.append(i)

Если мы посмотрим на результат:

--> print idx
[0, 4, 5, 6, 9]

--> print t[idx]
[ 0.  1.  2.  4.  5.]

вопрос в том, как это можно сделать более эффективно, особенно если массивы действительно длинные? Есть ли какие-то встроенные методы NumPy или SciPy, которые делают что-то подобное?

4 ответов


в то время как, как @1443118, я бы предложил использовать pandas, вы можете попробовать что-то с np.histogram.

во-первых, получить представление о Количество классов (интервалов min_dif s) вам понадобится:

>>> bins = np.arange(t[0], t[-1]+min_dif, min_dif) - 1e-12

на t[-1]+min_dif обеспечить берем последний момент -1e-12 хак, чтобы избежать 4.0 вашего примера, подсчитанного в последнем бункере: это просто смещение, чтобы убедиться, что мы закрываем интервалы справа.

>>> (counts, _) = np.histogram(t, bins)
>>> counts
array([4, 1, 1, 0, 3])
>>> counts.cumsum()
array([4, 5, 6, 6, 9])

и v[0:4] ваш первый образец, v[4:5] ваш второй... вы поняли идею.


простым решением будет интерполяция, используя, например,numpy.interp:

vsampled = numpy.interp(numpy.arange(t[0], t[-1]), t, v)

это не даст вам индексы значения. Однако он будет генерировать значения путем интерполяции даже для точек в t, где нет данных во входных массивах.


Я не могу придумать решение, как ровно то, что вы хотите, но пока это не представляется мне слишком вежливым, это примерно то, что вы хотите, не делая интерполяции. Он будет давать не более одного значения (самого левого) за каждую секунду:

# Assuming that t is sorted...
# Create all full seconds.
seconds = np.arange(int(t[0]), int(t[-1]) + 1)

# find the indexes for all
idx = np.searchsorted(t, seconds)
idx = np.unique(idx) # there might be duplicates if a second has no data in it.

для вашего примера он дает тот же результат, но, как правило, допускает меньшие или большие различия, конечно (что-то между 0 и 2 секундами)...


Я бы рекомендовал использовать панды для этого. Довольно просто генерировать регулярно разнесенные временные ряды, а затем перепроверять данные на определенную частоту. См.этой и посмотрите подраздел о повторной выборке примерно на полпути вниз по странице.