[英]Python: Slicing 2d NumPy array to produce order C arrays while using Numba
I've started using Numba and right now I'm trying speed up an algorithm using Numba.我已经开始使用 Numba,现在我正在尝试使用 Numba 加速算法。 However, I'm having trouble with a numpy.dot operation.
但是,我在执行 numpy.dot 操作时遇到了问题。 The problem is when I slice a 2d array of strings column-by-column it produces an array of type array([unichr x 100], 1d, A).
问题是当我逐列切片一个二维字符串数组时,它会生成一个类型为 array([unichr x 100], 1d, A) 的数组。 I need this type to be array([unichr x 100], 1d, C) in order for the numpy.where to produce an array of type array(float64, 1d, C).
我需要这种类型为 array([unichr x 100], 1d, C) 以便 numpy.where 生成类型为 array(float64, 1d, C) 的数组。 This array is then used in the numpy.dot operation with another array of the same type.
然后在 numpy.dot 操作中将此数组与另一个相同类型的数组一起使用。 Numba is telling me that I doesn't like the fact that the arrays have different orders, A and C. The algorithm works fine without Numba.
Numba 告诉我,我不喜欢数组具有不同的顺序,A 和 C。该算法在没有 Numba 的情况下工作正常。
Here is a short example to illustrate the problem.这里有一个简短的例子来说明这个问题。
data_X = [['a1','b2','c1'],
['a1','b2','c2'],
['a2','b1','c3'],
['a1','b2','c1'],
['a2','b1','c3']]
data_Y = [1.0, 2.0, 3.0, 4.0, 5.0]
X = np.array(data_X, dtype='<U100')
Y = np.array(data_Y, dtype=np.float64)
@nb.jit(
nopython=True,
locals={
'X': nb.types.Array(nb.types.UnicodeCharSeq(100), 2, 'C'),
'Y': nb.types.Array(nb.float64, 1, 'C'),
}
)
def func(X, Y):
results = []
for i in range(X.shape[1]):
uniqs = np.unique(X[:,i])
for u in uniqs:
X_vars = np.where(X[:,i] == np.full_like(X[:,i], u), 1.0, 0.0)
results.append(np.dot(X_vars, Y))
return results
func(X, Y)
The answer I get without Numba is [7.0, 8.0, 8.0, 7.0, 5.0, 2.0, 8.0].如果没有 Numba,我得到的答案是 [7.0, 8.0, 8.0, 7.0, 5.0, 2.0, 8.0]。 With Numba I get the following error:
使用 Numba 我收到以下错误:
<ipython-input-27-42fe2e73a7cd>:23: NumbaPerformanceWarning: np.dot() is faster on contiguous arrays, called on (array(float64, 1d, A), array(float64, 1d, C))
results.append(np.dot(X_vars, Y))
Traceback (most recent call last):
File "C:\DataScience\lib\site-packages\numba\core\errors.py", line 745, in new_error_context
yield
File "C:\DataScience\lib\site-packages\numba\core\lowering.py", line 273, in lower_block
self.lower_inst(inst)
File "C:\DataScience\lib\site-packages\numba\core\lowering.py", line 370, in lower_inst
val = self.lower_assign(ty, inst)
File "C:\DataScience\lib\site-packages\numba\core\lowering.py", line 544, in lower_assign
return self.lower_expr(ty, value)
File "C:\DataScience\lib\site-packages\numba\core\lowering.py", line 1266, in lower_expr
res = self.context.special_ops[expr.op](self, expr)
File "C:\DataScience\lib\site-packages\numba\np\ufunc\array_exprs.py", line 397, in _lower_array_expr
context, builder, outer_sig, args, ExprKernel, explicit_output=False)
File "C:\DataScience\lib\site-packages\numba\np\npyimpl.py", line 327, in numpy_ufunc_kernel
output = _build_array(context, builder, ret_ty, sig.args, arguments)
File "C:\DataScience\lib\site-packages\numba\np\npyimpl.py", line 281, in _build_array
dest_shape_tup)
File "C:\DataScience\lib\site-packages\numba\np\arrayobj.py", line 3385, in _empty_nd_impl
arrtype.layout))
NotImplementedError: Don't know how to allocate array with layout 'A'.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<ipython-input-27-42fe2e73a7cd>", line 26, in <module>
func(X, Y)
File "C:\DataScience\lib\site-packages\numba\core\dispatcher.py", line 434, in _compile_for_args
raise e
File "C:\DataScience\lib\site-packages\numba\core\dispatcher.py", line 367, in _compile_for_args
return self.compile(tuple(argtypes))
File "C:\DataScience\lib\site-packages\numba\core\compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "C:\DataScience\lib\site-packages\numba\core\dispatcher.py", line 808, in compile
cres = self._compiler.compile(args, return_type)
File "C:\DataScience\lib\site-packages\numba\core\dispatcher.py", line 78, in compile
status, retval = self._compile_cached(args, return_type)
File "C:\DataScience\lib\site-packages\numba\core\dispatcher.py", line 92, in _compile_cached
retval = self._compile_core(args, return_type)
File "C:\DataScience\lib\site-packages\numba\core\dispatcher.py", line 110, in _compile_core
pipeline_class=self.pipeline_class)
File "C:\DataScience\lib\site-packages\numba\core\compiler.py", line 603, in compile_extra
return pipeline.compile_extra(func)
File "C:\DataScience\lib\site-packages\numba\core\compiler.py", line 339, in compile_extra
return self._compile_bytecode()
File "C:\DataScience\lib\site-packages\numba\core\compiler.py", line 401, in _compile_bytecode
return self._compile_core()
File "C:\DataScience\lib\site-packages\numba\core\compiler.py", line 381, in _compile_core
raise e
File "C:\DataScience\lib\site-packages\numba\core\compiler.py", line 372, in _compile_core
pm.run(self.state)
File "C:\DataScience\lib\site-packages\numba\core\compiler_machinery.py", line 341, in run
raise patched_exception
File "C:\DataScience\lib\site-packages\numba\core\compiler_machinery.py", line 332, in run
self._runPass(idx, pass_inst, state)
File "C:\DataScience\lib\site-packages\numba\core\compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "C:\DataScience\lib\site-packages\numba\core\compiler_machinery.py", line 291, in _runPass
mutated |= check(pss.run_pass, internal_state)
File "C:\DataScience\lib\site-packages\numba\core\compiler_machinery.py", line 264, in check
mangled = func(compiler_state)
File "C:\DataScience\lib\site-packages\numba\core\typed_passes.py", line 442, in run_pass
NativeLowering().run_pass(state)
File "C:\DataScience\lib\site-packages\numba\core\typed_passes.py", line 370, in run_pass
lower.lower()
File "C:\DataScience\lib\site-packages\numba\core\lowering.py", line 179, in lower
self.lower_normal_function(self.fndesc)
File "C:\DataScience\lib\site-packages\numba\core\lowering.py", line 233, in lower_normal_function
entry_block_tail = self.lower_function_body()
File "C:\DataScience\lib\site-packages\numba\core\lowering.py", line 259, in lower_function_body
self.lower_block(block)
File "C:\DataScience\lib\site-packages\numba\core\lowering.py", line 273, in lower_block
self.lower_inst(inst)
File "C:\DataScience\lib\contextlib.py", line 130, in __exit__
self.gen.throw(type, value, traceback)
File "C:\DataScience\lib\site-packages\numba\core\errors.py", line 752, in new_error_context
reraise(type(newerr), newerr, tb)
File "C:\DataScience\lib\site-packages\numba\core\utils.py", line 81, in reraise
raise value
LoweringError: Don't know how to allocate array with layout 'A'.
First off, let's figure out where exactly numba is facing trouble.首先,让我们弄清楚 numba 到底在哪里面临问题。 If we simplify the operations down to:
如果我们将操作简化为:
def func(X, Y):
#results = []
for i in range(X.shape[1]):
uniqs = np.unique(X[:,i])
for u in uniqs:
X_vars = (X[:,i] == np.full_like(X[:,i], u))
#X_vars = np.where(X[:,i] == np.full_like(X[:,i], u), 1.0, 0.0)
#results.append(np.dot(X_vars, Y))
#return results
Then numba still continues to throw the same error: NotImplementedError: Don't know how to allocate array with layout 'A'
.然后 numba 仍然继续抛出相同的错误:
NotImplementedError: Don't know how to allocate array with layout 'A'
。 So this is where the problem is.所以这就是问题所在。 In fact, you can reproduce the same error with an even simpler operation:
事实上,您可以使用更简单的操作重现相同的错误:
def func(X, Y):
for i in range(X.shape[1]):
X[:,i] == X[:,i]
The stack trace provides a hint: the problem is in contiguity.堆栈跟踪提供了一个提示:问题出在连续性上。 Here,
X[:,i]
is a view and thus does not have 'C'/'F' contiguity specified, making numba go nuts.这里,
X[:,i]
是一个视图,因此没有指定 'C'/'F' 连续性,使 numba 发疯。 So a simple solution would be to add an extra line and apply np.ascontiguousarray
on your view.因此,一个简单的解决方案是添加额外的行并在您的视图上应用
np.ascontiguousarray
。 A deep copy would also work just as well.深拷贝也同样有效。
@nb.jit(
nopython=True,
locals={
'X': nb.types.Array(nb.types.UnicodeCharSeq(100), 2, 'C'),
'Y': nb.types.Array(nb.float64, 1, 'C'),
}
)
def func(X, Y):
results = []
for i in range(X.shape[1]):
X_i = np.ascontiguousarray(X[:,i])
uniqs = np.unique(X_i)
for u in uniqs:
X_vars = np.where( X_i == np.full_like(X_i, u), 1.0, 0.0)
results.append(np.dot(X_vars, Y))
return results
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.