【发布时间】:2020-03-10 19:56:34
【问题描述】:
给出以下最小可重现示例:
import numpy as np
from numba import jit
# variable number of dimensions
n_t = 8
# q is just a partition of n
q_ddl = 2
n_ddl = 3
np.random.seed(42)
df = np.random.rand(q_ddl*n_t,q_ddl*n_t)
# index array
# ddl_nl is a set of np.arange(n_ddl), ex: [0,1] ; [0,2] or even [0] ...
ddl_nl = np.array([0,1])
ij = np.asarray(np.meshgrid(ddl_nl,ddl_nl,indexing='ij'))
@jit(nopython=True)
def foo(df,ij):
out = np.zeros((n_t,n_ddl,n_ddl))
for i in range(0,n_t):
d_i = np.zeros((n_ddl,n_ddl))
# (q_ddl,q_ddl) non zero values into (n_ddl,n_ddl) shape
d_i[ij[0], ij[1]] = df[i::n_t,i::n_t]
# to check possible solutions
out[i,...] = d_i
return out
out_foo = foo(df,ij)
foo 函数在 @jit(nopython=True) 被禁用时运行良好,但在启用时抛出以下错误:
TypeError: unsupported array index type array(int64, 2d, C) in UniTuple(array(int64, 2d, C) x 2)
在广播操作d_i[ij[0], ij[1]] = df[i::n_t,i::n_t] 期间发生。然后,我确实尝试使用类似d_i[ij[0].ravel(), ij[1].ravel()] = df[i::n_t,i::n_t].ravel() 的东西来展平二维索引数组ij,这给了我相同的输出,但现在又出现了另一个错误:
NotImplementedError: only one advanced index supported
所以我最终尝试通过使用经典的 2 嵌套 for 循环结构来避开这个问题:
tmp = df[i::n_t,i::n_t]
for k,r in enumerate(ddl_nl):
for l,c in enumerate(ddl_nl):
d_i[r,c] = tmp[k,l]
启用装饰器并提供预期结果。
但是我不能停止思考是否有任何我在这里缺少的 numpy 2d-array 广播操作兼容 numba 的替代方案?任何帮助将不胜感激。
【问题讨论】:
-
定义“numba 友好”:)
-
meshgrid 是否也在您的实际功能中?维度的数量总是相同的吗?对于此示例,您根本不需要网格网格或花哨的索引之类的东西。即使它可以工作,它也会比简单的嵌套循环慢。使用像 n_t 这样的 gloabls 也是不推荐的(如果不重新编译就无法更改它们)
-
维数并不总是相同的......但是q只是n的一个分区。对 numba 友好,我的意思是 numba 兼容。你 2 是对的,感谢这些答案,在这种情况下,for 循环与花哨的方法一样快(甚至更快),我想我会走这条路。