Линейная интерполяция двух 2D-массивов

avatar
ahwillia
8 апреля 2018 в 01:43
2427
1
5

В предыдущем вопросе (самый быстрый способ использования numpy.interp в двумерном массиве) кто-то попросил самый быстрый способ реализовать следующее:

np.array([np.interp(X[i], x, Y[i]) for i in range(len(X))])

предположим, что X и <19455557417352> являются матрицами со многими строками, поэтому цикл for является дорогостоящим. В этом случае есть хорошее решение, позволяющее избежать цикла for (см. связанный ответ выше).


Я столкнулся с очень похожей проблемой, но мне непонятно, можно ли в этом случае избежать цикла for:

np.array([np.interp(x, X[i], Y[i]) for i in range(len(X))])

Другими словами, я хочу использовать линейную интерполяцию для повышения дискретизации большого количества сигналов, хранящихся в строках двух матриц X и Y. Я надеялся найти функцию в numpy или scipy (scipy.interpolate.interp1d), которая поддерживала бы эту операцию с помощью широковещательной семантики, но пока не могу ее найти.

Другие пункты:

  • Если это поможет, строки X[i] и x предварительно отсортированы в моем приложении. Кроме того, в моем случае len(x) немного больше, чем len(X[i]).

  • Функция scipy.signal.resample почти делает то, что я хочу, но не использует линейную интерполяцию...

Источник

Ответы (1)

avatar
user6655984
9 апреля 2018 в 02:46
4

Это векторизованный подход, непосредственно реализующий линейную интерполяцию. Во-первых, для каждого значения x и каждого i, j вычислите вес w, выражающий, какая часть интервала (X[i, j], X[i, j+1]) находится слева от x.

  • Если весь интервал находится слева от x, вес этого интервала равен 1.
  • Если ни один из подынтервалов не находится слева, вес равен 0
  • В противном случае вес представляет собой число от 0 до 1, выражающее долю этого интервала слева от x.

Затем значение интерполянта PL вычисляется как Y[i, 0] + сумма разностей dY[i, j], умноженная на соответствующий вес. Логика заключается в том, чтобы следить за тем, насколько интерполянт меняется от интервала к интервалу. Разности dY = np.diff(Y, axis=1) показывают, насколько она меняется на всем интервале. Умножение на пропорции веса, которые соответственно изменяются.

Настройка с небольшими массивами данных

import numpy as np
X = np.array([[0, 2, 5, 6, 9], [1, 3, 4, 7, 8]])
Y = np.array([[3, 5, 2, 4, 1], [8, 6, 9, 5, 4]])
x = np.linspace(1, 8, 20)

Вычисление

dX = np.diff(X, axis=1)
dY = np.diff(Y, axis=1)
w = np.clip((x - X[:, :-1, None])/dX[:, :, None], 0, 1)
y = Y[:, [0]] + np.sum(w*dY[:, :, None], axis=1)

Демонстрация

Это только для того, чтобы показать, что интерполяция верна. Синие точки: исходные данные, красные вычисляются.

import matplotlib.pyplot as plt
plt.plot(x, y[0], 'ro')
plt.plot(X[0], Y[0], 'bo')
plt.plot(x, y[1], 'rd')
plt.plot(X[1], Y[1], 'bd')
plt.show()

PL interpolants

jessexknight
11 февраля 2019 в 15:02
0

Это предполагает, что все элементы (X, Y) имеют одинаковую длину: \