Numpy:向量化双分支测试(类似三元运算符)
Numpy: vectorizing two-branch test (ternary-operator like)
我正在 Numpy 中对一个测试进行矢量化以实现以下想法:执行 elementwise 一些测试并选择 expr1 或 expr2 根据测试。这就像 C 中的 三元运算符 : test?expr1:expr2
我看到了两种主要的执行方式;我想知道是否有充分的理由选择一个而不是另一个;也许还有其他技巧可用,我很乐意了解它们。主要目标是速度;因此,我不想将 np.vectorize
与 if-else
语句一起使用。
对于我的示例,我将重新构建 min
函数;请不要告诉我一些用于计算的 Numpy 函数;这只是一个例子!
思路一:在乘法中使用布尔的算术值:
# a and b have similar shape
test = a < b
ntest = np.logical_not(test)
out = test*a + ntest*b
想法 2:或多或少遵循 APL/J 编码风格(通过使用条件表达式作为数组的索引,该数组的维度比初始维度大数组)。
# a and b have similar shape
np.choose(a<b, np.array([b,a]))
这是更好的使用方法 choose
np.choose(a<b, [b,a])
在我的小时间里它更快。 choose
文档还说 If
choicesis itself an array (not recommended), ....
(a<b).choose([b,a])
节省一级函数重定向。
另一种选择:
out = b.copy(); out[test] = a[test]
在快速测试中,这实际上更快。 masked.filled
使用 np.copyto
进行这种 'where' 复制,尽管它似乎并没有更快。
choose
的变体是 where
:
np.where(test,a,b)
或使用where
(或np.nonzero
)将布尔索引转换为数字索引:
I = np.where(test); out = b.copy(); out[I] = a[I]
出于某种原因,这个时间比一件式快得多。
我过去使用过乘法方法;如果我没记错的话,即使是 APL(尽管那是几十年前)。避免除以 0 的一个老技巧是添加 n==0
、a/(b+(b==0))
。但它并不普遍适用。 a*0
、a*1
要有道理。
choose
看起来不错,但是使用 mode
参数可能会更强大(因此更复杂)。
我不确定是否有 'best' 方法。时序测试可以评估某些情况,但我不知道它们在哪里可以推广到所有情况。
我正在 Numpy 中对一个测试进行矢量化以实现以下想法:执行 elementwise 一些测试并选择 expr1 或 expr2 根据测试。这就像 C 中的 三元运算符 : test?expr1:expr2
我看到了两种主要的执行方式;我想知道是否有充分的理由选择一个而不是另一个;也许还有其他技巧可用,我很乐意了解它们。主要目标是速度;因此,我不想将 np.vectorize
与 if-else
语句一起使用。
对于我的示例,我将重新构建 min
函数;请不要告诉我一些用于计算的 Numpy 函数;这只是一个例子!
思路一:在乘法中使用布尔的算术值:
# a and b have similar shape
test = a < b
ntest = np.logical_not(test)
out = test*a + ntest*b
想法 2:或多或少遵循 APL/J 编码风格(通过使用条件表达式作为数组的索引,该数组的维度比初始维度大数组)。
# a and b have similar shape
np.choose(a<b, np.array([b,a]))
这是更好的使用方法 choose
np.choose(a<b, [b,a])
在我的小时间里它更快。 choose
文档还说 If
choicesis itself an array (not recommended), ....
(a<b).choose([b,a])
节省一级函数重定向。
另一种选择:
out = b.copy(); out[test] = a[test]
在快速测试中,这实际上更快。 masked.filled
使用 np.copyto
进行这种 'where' 复制,尽管它似乎并没有更快。
choose
的变体是 where
:
np.where(test,a,b)
或使用where
(或np.nonzero
)将布尔索引转换为数字索引:
I = np.where(test); out = b.copy(); out[I] = a[I]
出于某种原因,这个时间比一件式快得多。
我过去使用过乘法方法;如果我没记错的话,即使是 APL(尽管那是几十年前)。避免除以 0 的一个老技巧是添加 n==0
、a/(b+(b==0))
。但它并不普遍适用。 a*0
、a*1
要有道理。
choose
看起来不错,但是使用 mode
参数可能会更强大(因此更复杂)。
我不确定是否有 'best' 方法。时序测试可以评估某些情况,但我不知道它们在哪里可以推广到所有情况。