Прошлой ночью я некоторое время пытался использовать различные различные функции numpy векторизации для задачи (что, без всякого сомнения, вполне выполнимо без них) для создания линейных интерполяций между точками.
Допустим, У меня есть вектор с плавающей точкой (назовем их «точками»),
v = np.array([9. , 1. , 4.2, 5.6, 3. , 4.6])
Я хочу интерполировать между соседними точками, поэтому мне нужно взять эти пары:
def adjacent_pairs(v):
"""
Given a 1D numpy array `v = np.array([1, ..., n])`, return a 2D numpy array of
adjacent pairs, `np.array([(1,2), ..., (n-1,n)])`.
"""
s = v.shape
d = len(s)
assert d == 1, ValueError(f"Vector must be 1D - got a {d}D vector: shape = {s})")
return np.vstack([v[:-1],v[1:]]).T
adjacent_pairs(v)
дает:
array([[9. , 1. ],
[1. , 4.2],
[4.2, 5.6],
[5.6, 3. ],
[3. , 4.6]])
Я хочу интерполировать эти пары (строки матрицы, например, [9., 1.]
) с интервалами размера 0,2, но интерполяции могут быть восходящими или нисходящими, поэтому я нормализую разностный вектор, чтобы найти «направление» или знак (+1 при возрастании, -1 при спуске) и умножить его на размер шага, чтобы передать arange
в качестве аргумента step
.
Это работает:
def interpolate_1d(v, step=0.2):
v_adj = adjacent_pairs(v)
d = np.diff(v_adj) / np.abs(np.diff(v_adj))
interpolated = [np.arange(*r, diff * step) for r, diff in zip(v_adj, d)]
return interpolated
Однако я осознаю, что часть zip()
не находится "в" numpy, и, возможно, я должен был бы сделать это таким образом.
I начал изучать различные «векторизованные» функции в * 107 7 * (что, как я понимаю, иногда может ускорить ваш код), но у меня возникают проблемы с переформатированием этого кода в абстракции np.fromiter
, np.vectorize
или np.frompyfunc
, и через несколько часов вчера вечером я ' Я надеюсь, что кто-то, более знакомый с ними, может объяснить мне, как я могу использовать один или несколько из них с моим кодом.
Я бы предпочел передать строку и знак разницы отдельно (как lambda row, diff: ...
), но мне не удалось заставить их работать, поэтому я hstack
отредактировал массивы v_adj
и d
, чтобы каждая строка содержала их обоих (и мне понадобился бы только один аргумент для лямбды) .
Вот две версии функции:
def interpolate_1d_vectorised(v, step=0.2):
"""
Couldn't get this to work: how to expand out the two parts at a time to pass to
the lambda function?
"""
v_adj = adjacent_pairs(v)
d = np.diff(v_adj) / np.abs(np.diff(v_adj))
# lambda_func = lambda row, diff: np.arange(*row, diff * step)
lambda_func = lambda row, diff: np.arange(row[0], row[1], diff * step)
row_arange = np.vectorize(lambda_func, signature="(),()->()")
interpolated = row_arange(v_adj, d)
return interpolated
def interpolate_1d_vectorised_triples(v, step=0.2):
v_adj = adjacent_pairs(v)
d = np.diff(v_adj) / np.abs(np.diff(v_adj))
triples = np.hstack([v_adj, d])
triple_lambda = lambda t: np.arange(t[0], t[1], t[2] * step)
row_arange_t = np.vectorize(triple_lambda, signature="()->()")
interpolated = row_arange_t(triples)
return interpolated
Некоторые примеры ошибок, которые я получил:
ValueError: setting an array element with a sequence.
- из
row_arange(v_adj, d)
где row_arange = np.vectorize(lambda_func, signature="(),()->()")
(как в interpolate_1d_vectorised
) - также из
np.fromiter([np.arange(a,b,c * step) for (a,b,c) in triples])
Я попытался отладить с помощью лямбда-функции, которая просто печатает значений, над которыми он работает, и кажется, что векторизация происходит для каждого значения в массиве, а не накануне ry row (это то, что я хотел бы). Похоже, это объясняет сообщение об ошибке, но мне все еще неясно, как принимать три значения за раз (или строку за раз) в качестве входных данных для векторизованной функции и создавать один выходной для каждого входа.
Я использовал np.apply_along_axis
и np.apply_over_axes
ранее, но я тоже получал различные ошибки, используя их.
Я ожидал, что это сработает:
triple_lambda = lambda t: np.arange(t[0], t[1], t[2] * 0.2)
np.apply_along_axis(triple_lambda, 1, triples)
, но это дало: ValueError: could not broadcast input array from shape (16) into shape (40)
, что, как я предполагаю, означает, что интерполированные значения делают вектор больше.
np.apply_over_axes(triple_lambda, triples, axes=[0,2])
дал TypeError: <lambda>() takes 1 positional argument but 2 were given
(то же самое, когда axes=[0,1]
).
(Это было о точке, которую я дал up)
Извините, если это приложение не подходит для этих функций, пожалуйста, дайте мне знать, если для этого есть что-то еще лучше (и что, если что-то, для чего эти функции будут использоваться вместо этого). Я собирался просто удалить эти попытки и двигаться дальше, но подумал, что мне следует спросить здесь, чтобы я мог научиться использовать эти функции в будущем. Любой совет высоко ценится!