【发布时间】:2020-04-21 13:01:26
【问题描述】:
我昨晚尝试了一段时间,将各种不同的 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]])
我想按大小为 0.2 的间隔对这些对(矩阵的行,例如 [9., 1.])进行插值,但插值可能是升序或降序,因此我将差异向量归一化以找到“方向”或符号(+1 表示升序,-1 表示降序)并将其乘以步长以作为 step 参数传递给 arange。
这行得通:
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,也许我应该这样做。
我开始研究 numpy 中的各种“矢量化”函数(据我所知,它有时可以加速您的代码),但我无法将此代码重新格式化为 np.fromiter、np.vectorize 的抽象,或np.frompyfunc,昨晚几个小时后,我希望更熟悉这些的人能启发我如何在我的代码中使用其中的一个或多个。
我更喜欢分别传递行和差异符号(如lambda row, diff: ...),但我无法让这些工作,所以我hstacked v_adj 和 d数组,以便每一行都包含它们(我只需要一个 lambda 参数)。
这里是函数的两个版本:
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])
- 来自
我尝试使用 lambda 函数进行调试,该函数仅打印出它正在处理的值,并且似乎矢量化发生在数组中的每个值上,而不是每一行(这是我想要的)。这似乎解释了错误消息,但我仍然不清楚如何一次将三个值(或一次一行)作为向量化函数的输入,并为每个输入生成一个输出。
我之前使用过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] 时相同)。
(这是我放弃的重点)
很抱歉,如果这不是使用这些函数的正确应用程序,请告诉我是否还有其他更好的用途(如果这些函数可以用于其他用途)。我本来打算删除这些尝试并继续前进,但我想我应该在这里问一下,这样我将来可能会学习如何使用这些功能。非常感谢任何建议!
【问题讨论】:
-
没有这些功能,
np.vectorize``,np.apply...` 加速你的代码。np.vectorize有明确的免责声明。有时它们在编写循环很尴尬时很方便,但它们不是您正在寻找的加速工具。 -
是的,我确实看到了免责声明,这就是为什么我“有时”添加了关于它们的注释。我仍然想了解如何使用它们。我尝试以这种格式重写的主要原因是摆脱看起来不像 numpy-ish 的
list(zip())构造 -
干得好。 np.repeat 是这种非常量间隔大小的技巧
标签: python numpy numpy-ufunc