在二维数组列上映射 Dask bincount
Map Dask bincount over 2d array columns
我正在尝试对二维数组使用 bincount。具体来说,我有这段代码:
import numpy as np
import dask.array as da
def dask_bincount(weights, x):
da.bincount(x, weights)
idx = da.random.random_integers(0, 1024, 1000)
weight = da.random.random((1000, 2))
bin_count = da.apply_along_axis(dask_bincount, 1, weight, idx)
我们的想法是,可以在每个权重列上使用相同的 idx 数组创建 bincount。如果我是正确的,那将 return 一个大小为 (np.amax(x) + 1, 2) 的数组。
但是,这样做时我收到此错误消息:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-17-5b8eed89ad32> in <module>
----> 1 bin_count = da.apply_along_axis(dask_bincount, 1, weight, idx)
~/.local/lib/python3.9/site-packages/dask/array/routines.py in apply_along_axis(func1d, axis, arr, dtype, shape, *args, **kwargs)
454 if shape is None or dtype is None:
455 test_data = np.ones((1,), dtype=arr.dtype)
--> 456 test_result = np.array(func1d(test_data, *args, **kwargs))
457 if shape is None:
458 shape = test_result.shape
<ipython-input-14-34fd0eb9b775> in dask_bincount(weights, x)
1 def dask_bincount(weights, x):
----> 2 da.bincount(x, weights)
~/.local/lib/python3.9/site-packages/dask/array/routines.py in bincount(x, weights, minlength, split_every)
670 raise ValueError("Input array must be one dimensional. Try using x.ravel()")
671 if weights is not None:
--> 672 if weights.chunks != x.chunks:
673 raise ValueError("Chunks of input array x and weights must match.")
674
AttributeError: 'numpy.ndarray' object has no attribute 'chunks'
我以为创建 dask 数组时库会自动为它们分配块,所以错误并没有说明太多。我该如何解决这个问题?
我用 map
在 numpy 上做了一个脚本。
idx_np = np.random.randint(0, 1024, 1000)
weight_np = np.random.random((1000,2))
f = lambda y: np.bincount(idx_np, weight_np[:,y])
result = map(f, [i for i in range(2)])
np.array(list(result))
array([[0.9885341 , 0.9977873 , 0.24937023, ..., 0.31024526, 1.40754883,
0.87609759],
[1.77406303, 0.84787723, 0.14591474, ..., 0.54584068, 0.38357015,
0.85202672]])
我也想这样做,但有 dask
有多个问题在起作用。
权重应该是(2, 1000)
您通过尝试使用 apply_along_axis
在 numpy 中编写相同的函数来发现这一点。
idx_np = np.random.random_integers(0, 1024, 1000)
weight_np = np.random.random((2, 1000)) # <- transposed
# This gives the same result as the code you provided
np.apply_along_axis(lambda weight, idx: np.bincount(idx, weight), 1, weight_np, idx_np)
da.apply_along_axis
将函数应用于 numpy 数组
你遇到了错误
AttributeError: 'numpy.ndarray' object has no attribute 'chunks'
这表明进入 da.bincount
方法的实际上是一个 numpy 数组。事实是 da.apply_along_axis
实际上获取 weight
的每一行并将其作为 numpy 数组发送到函数。
因此,您的函数实际上应该是一个 numpy 函数:
def bincount(weights, x):
return np.bincount(x, weights)
但是,如果您尝试这样做,您仍然会遇到同样的错误。我相信这完全是另一个原因:
Dask 不知道输出形状是什么并试图推断它
在 apply_along_axis
的代码 and/or 文档中,我们可以看到 Dask 试图推断输出形状和 dtype by passing in the array [1]
(related question)。这是个问题,因为 bincount
不能接受这样的论点。
我们可以做的是为方法提供 shape
和 dtype
,这样 Dask 就不必推断它了。
这里的问题是bincount
的输出形状取决于输入数组的最大值。除非您事先知道,否则您将很遗憾地需要计算它。因此整个操作不会完全懒惰。
这是完整答案:
import numpy as np
import dask.array as da
idx = da.random.random_integers(0, 1024, 1000)
weight = da.random.random((2, 1000))
def bincount(weights, x):
return np.bincount(x, weights)
m = idx.max().compute()
da.apply_along_axis(bincount, 1, weight, idx, shape=(m,), dtype=weight.dtype)
附录:randint
对比 random_integers
小心,因为它们有细微的不同
randint
取从 low
(含)到 high
(不含)的整数
random_integers
取从low
(含)到high
(含)的整数
因此您必须调用 randint
和 high + 1
以获得相同的值。
我正在尝试对二维数组使用 bincount。具体来说,我有这段代码:
import numpy as np
import dask.array as da
def dask_bincount(weights, x):
da.bincount(x, weights)
idx = da.random.random_integers(0, 1024, 1000)
weight = da.random.random((1000, 2))
bin_count = da.apply_along_axis(dask_bincount, 1, weight, idx)
我们的想法是,可以在每个权重列上使用相同的 idx 数组创建 bincount。如果我是正确的,那将 return 一个大小为 (np.amax(x) + 1, 2) 的数组。 但是,这样做时我收到此错误消息:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-17-5b8eed89ad32> in <module>
----> 1 bin_count = da.apply_along_axis(dask_bincount, 1, weight, idx)
~/.local/lib/python3.9/site-packages/dask/array/routines.py in apply_along_axis(func1d, axis, arr, dtype, shape, *args, **kwargs)
454 if shape is None or dtype is None:
455 test_data = np.ones((1,), dtype=arr.dtype)
--> 456 test_result = np.array(func1d(test_data, *args, **kwargs))
457 if shape is None:
458 shape = test_result.shape
<ipython-input-14-34fd0eb9b775> in dask_bincount(weights, x)
1 def dask_bincount(weights, x):
----> 2 da.bincount(x, weights)
~/.local/lib/python3.9/site-packages/dask/array/routines.py in bincount(x, weights, minlength, split_every)
670 raise ValueError("Input array must be one dimensional. Try using x.ravel()")
671 if weights is not None:
--> 672 if weights.chunks != x.chunks:
673 raise ValueError("Chunks of input array x and weights must match.")
674
AttributeError: 'numpy.ndarray' object has no attribute 'chunks'
我以为创建 dask 数组时库会自动为它们分配块,所以错误并没有说明太多。我该如何解决这个问题?
我用 map
在 numpy 上做了一个脚本。
idx_np = np.random.randint(0, 1024, 1000)
weight_np = np.random.random((1000,2))
f = lambda y: np.bincount(idx_np, weight_np[:,y])
result = map(f, [i for i in range(2)])
np.array(list(result))
array([[0.9885341 , 0.9977873 , 0.24937023, ..., 0.31024526, 1.40754883,
0.87609759],
[1.77406303, 0.84787723, 0.14591474, ..., 0.54584068, 0.38357015,
0.85202672]])
我也想这样做,但有 dask
有多个问题在起作用。
权重应该是(2, 1000)
您通过尝试使用 apply_along_axis
在 numpy 中编写相同的函数来发现这一点。
idx_np = np.random.random_integers(0, 1024, 1000)
weight_np = np.random.random((2, 1000)) # <- transposed
# This gives the same result as the code you provided
np.apply_along_axis(lambda weight, idx: np.bincount(idx, weight), 1, weight_np, idx_np)
da.apply_along_axis
将函数应用于 numpy 数组
你遇到了错误
AttributeError: 'numpy.ndarray' object has no attribute 'chunks'
这表明进入 da.bincount
方法的实际上是一个 numpy 数组。事实是 da.apply_along_axis
实际上获取 weight
的每一行并将其作为 numpy 数组发送到函数。
因此,您的函数实际上应该是一个 numpy 函数:
def bincount(weights, x):
return np.bincount(x, weights)
但是,如果您尝试这样做,您仍然会遇到同样的错误。我相信这完全是另一个原因:
Dask 不知道输出形状是什么并试图推断它
在 apply_along_axis
的代码 and/or 文档中,我们可以看到 Dask 试图推断输出形状和 dtype by passing in the array [1]
(related question)。这是个问题,因为 bincount
不能接受这样的论点。
我们可以做的是为方法提供 shape
和 dtype
,这样 Dask 就不必推断它了。
这里的问题是bincount
的输出形状取决于输入数组的最大值。除非您事先知道,否则您将很遗憾地需要计算它。因此整个操作不会完全懒惰。
这是完整答案:
import numpy as np
import dask.array as da
idx = da.random.random_integers(0, 1024, 1000)
weight = da.random.random((2, 1000))
def bincount(weights, x):
return np.bincount(x, weights)
m = idx.max().compute()
da.apply_along_axis(bincount, 1, weight, idx, shape=(m,), dtype=weight.dtype)
附录:randint
对比 random_integers
小心,因为它们有细微的不同
randint
取从low
(含)到high
(不含)的整数random_integers
取从low
(含)到high
(含)的整数
因此您必须调用 randint
和 high + 1
以获得相同的值。