从 numpy 数组创建一组切片,用于并行化
Create a set of slices from a numpy array, for parallelization
我有一个类似 ids = ([0,0,0,1,1,2,2,2,2,4,5,5,5])
的 numpy 数组和一些其他长度相同的 numpy 数组(比如 a
和 b
)。我想使用这些数组的切片执行一些独立的操作,这些切片定义为共享相同(连续)一组 id 的索引。 IE。我想定义一组像
这样的切片
slice_0 = 0:3
slice_1 = 3:5
slice_2 = 5:9
...
这样我就可以为每个 n 并行调用一个函数 f(a[slice_n],b[slice_n])
。如何在 numpy 中构造切片?如果有帮助,在 R 中我会用 tapply
.
之类的东西来做
我不确定我理解你的问题,也许你是故意的
slice_0 = 0:3
slice_1 = 3:5
slice_2 = 5:9
slice_3 = 9:10
slice_4 = 10:13
如果是这种情况,可以使用NumPy的unique:
_, idx, count = numpy.unique(ids, return_index=True, return_counts=True)
切片的下限为idx
,上限为idx + count
。
一种方法:
In [12]: arrays=vstack((a,b))
In [13]: arrays
Out[13]:
array([[4, 1, 4, 2, 5, 7, 1, 5, 9],
[8, 1, 1, 1, 9, 3, 0, 3, 1]])
In [14]: subarrays=np.split(arrays,[3,5],axis=1)
In [15]: subarrays
Out[15]:
[array([[4, 1, 4],
[8, 1, 1]]),
array([[2, 5],
[1, 9]]),
array([[7, 1, 5, 9],
[3, 0, 3, 1]])]
In [16]: [multiply(a,b) for (a,b) in subarrays]
Out[16]: [array([32, 1, 4]), array([ 2, 45]), array([21, 0, 15, 9])]
如果你想沿着一个轴将数组分割成块,最简单的方法是 np.split
:
>>> a = np.arange(10)
>>> split_points = (2,5,7)
>>> np.split(a, split_points)
[array([0, 1]), array([2, 3, 4]), array([5, 6]), array([7, 8, 9])]
如果你想要均匀分割,你可以使用 np.arange
代替 split_points
。
要从 id 数组创建分割点,请使用 split_points = np.where(np.diff(ids))[0] + 1
如果您的 ID 数组已排序并且您的 ID 没有重复,那么 split_points = np.searchsorted(ids, ids_wor)[1:]
可能会更快。
获得你的分裂点:
spl=np.r_[0, np.where(np.nonzero(np.diff(ids)))[0] + 1, ids.size]
然后是切片列表
slices=[slice(i,j) for i,j in zip(spl[:-1].flat, spl[1:].flat)]
或拆分您的其他阵列
a_spl=np.split(a,spl[1:-1])
编辑:由于 idx
已排序并按顺序排列,您可以执行上面的 unique
或执行布尔切片(如果您有记忆)
slices = list(np.unique(ids)[:,None] == ids[None,:])
我有一个类似 ids = ([0,0,0,1,1,2,2,2,2,4,5,5,5])
的 numpy 数组和一些其他长度相同的 numpy 数组(比如 a
和 b
)。我想使用这些数组的切片执行一些独立的操作,这些切片定义为共享相同(连续)一组 id 的索引。 IE。我想定义一组像
slice_0 = 0:3
slice_1 = 3:5
slice_2 = 5:9
...
这样我就可以为每个 n 并行调用一个函数 f(a[slice_n],b[slice_n])
。如何在 numpy 中构造切片?如果有帮助,在 R 中我会用 tapply
.
我不确定我理解你的问题,也许你是故意的
slice_0 = 0:3
slice_1 = 3:5
slice_2 = 5:9
slice_3 = 9:10
slice_4 = 10:13
如果是这种情况,可以使用NumPy的unique:
_, idx, count = numpy.unique(ids, return_index=True, return_counts=True)
切片的下限为idx
,上限为idx + count
。
一种方法:
In [12]: arrays=vstack((a,b))
In [13]: arrays
Out[13]:
array([[4, 1, 4, 2, 5, 7, 1, 5, 9],
[8, 1, 1, 1, 9, 3, 0, 3, 1]])
In [14]: subarrays=np.split(arrays,[3,5],axis=1)
In [15]: subarrays
Out[15]:
[array([[4, 1, 4],
[8, 1, 1]]),
array([[2, 5],
[1, 9]]),
array([[7, 1, 5, 9],
[3, 0, 3, 1]])]
In [16]: [multiply(a,b) for (a,b) in subarrays]
Out[16]: [array([32, 1, 4]), array([ 2, 45]), array([21, 0, 15, 9])]
如果你想沿着一个轴将数组分割成块,最简单的方法是 np.split
:
>>> a = np.arange(10)
>>> split_points = (2,5,7)
>>> np.split(a, split_points)
[array([0, 1]), array([2, 3, 4]), array([5, 6]), array([7, 8, 9])]
如果你想要均匀分割,你可以使用 np.arange
代替 split_points
。
要从 id 数组创建分割点,请使用 split_points = np.where(np.diff(ids))[0] + 1
如果您的 ID 数组已排序并且您的 ID 没有重复,那么 split_points = np.searchsorted(ids, ids_wor)[1:]
可能会更快。
获得你的分裂点:
spl=np.r_[0, np.where(np.nonzero(np.diff(ids)))[0] + 1, ids.size]
然后是切片列表
slices=[slice(i,j) for i,j in zip(spl[:-1].flat, spl[1:].flat)]
或拆分您的其他阵列
a_spl=np.split(a,spl[1:-1])
编辑:由于 idx
已排序并按顺序排列,您可以执行上面的 unique
或执行布尔切片(如果您有记忆)
slices = list(np.unique(ids)[:,None] == ids[None,:])