Python 不使用直接掩蔽的numpy数组条件矢量化计算

Python 不使用直接掩蔽的numpy数组条件矢量化计算,python,numpy,conditional-statements,vectorization,Python,Numpy,Conditional Statements,Vectorization,我想问一下,是否可以使用用户定义的func,或者利用最快的方法?我曾想过使用索引,但发现它很有挑战性,因为使用[row\u ind,co\u ind]的切片元素是选定元素的一维数组。我看到可以使用重塑将切片矩阵放入矩阵,但有没有一种优雅的方法?理想情况下,这种r\u mat+a操作可以由用户定义的函数代替。用户定义的函数绝对可以有一个矢量化解决方案,只要该函数在1D数组上矢量化为工作元素(这对于任何使用现成numpy函数编写的内容都是如此) 假设你有r\u mat作为(m,n)矩阵和a\u数组作


我想问一下,是否可以使用用户定义的func,或者利用最快的方法?我曾想过使用索引,但发现它很有挑战性,因为使用
[row\u ind,co\u ind]
的切片元素是选定元素的一维数组。我看到可以使用
重塑
将切片矩阵放入矩阵,但有没有一种优雅的方法?理想情况下,这种
r\u mat+a
操作可以由用户定义的函数代替。

用户定义的函数绝对可以有一个矢量化解决方案,只要该函数在1D数组上矢量化为工作元素(这对于任何使用现成numpy函数编写的内容都是如此)

假设你有
r\u mat
作为
(m,n)
矩阵和
a\u数组
作为
(m,)
向量。您可以编写函数来接受挂钩。每个钩子可以是常量,也可以是可调用的。如果它是可调用的,则使用两个长度相同的数组调用它,并且必须返回第三个长度相同的数组。您可以随意更改该合同以包含索引或任何您想要的内容:

def f(r_mat, a_array, hook11, hook01, hook10, hook00):
    a = a_array[:, None]  # to column vector

    row_mask = (r_mat.mean(axis=1) > 2)[:,None]
    elem_mask = r_mat >= a

    out = np.empty_like(r_mat)

    def apply_hook(mask, hook):
        r, c = np.nonzero(mask)
        out[r, c] = hook(r_mat[r, c], a_array[r]) if callable(hook) else hook

    apply_hook(row_mask & elem_mask, hook11)
    apply_hook(~row_mask & elem_mask, hook01)
    apply_hook(row_mask & ~elem_mask, hook10)
    apply_hook(~row_mask & ~elem_mask, hook00)

    return out
代码中的当前配置的调用方式如下

f(r_mat, a_array, np.subtract, np.add, np.nan, 0)
假设你想做比np.subtract更复杂的事情。例如,您可以执行以下操作:

def my_complicated_func(r, a):
    return np.cumsum(r, a) - 3 * r // a + np.exp(a)

f(r_mat, a_array, my_complicated_func, np.add, np.nan, 0.0)
关键是
my\u complexed\u func
对数组进行操作。它将被传递
r\u mat
元素的子集,并且
a\u数组
元素将根据需要沿着每行重复多次

您还可以通过函数了解每个位置的索引来执行相同的操作。只需调用
hook
作为
hook(r_mat[r,c],a_数组[r],r,c)
。现在,钩子函数必须接受两个附加参数。原始代码将相当于

f(r_mat, a_array, lambda r, a, *args: np.subtract(r, a), lambda r, a, *args: np.add(r, a), np.nan, 0)

简而言之,答案是否定的,如果没有循环,就不能拥有完全任意的用户定义func。但是,您可以强制用户提供接受
where
作为参数的func。等等,不管怎样。你以前几乎已经回答了你自己的问题。将立即发布。
np.frompyfunc
确实创建了一个
ufunc
,它将
中取出
,但速度与内置的
ufunc
完全不同。“hook”方法与本例中的直接掩蔽方法类似,或稍慢一点。这是灵活性的代价。在某些情况下,使用索引可能会稍微快一些,因为它不需要额外的过程来确定输出大小。取决于掩模密度和输入大小。
f(r_mat, a_array, lambda r, a, *args: np.subtract(r, a), lambda r, a, *args: np.add(r, a), np.nan, 0)