没有直接从 NumPy 数组中提取多个切片的好方法,更不用说不同大小的切片了。但是您可以通过将切片转换为索引并使用索引数组来作弊。
对于一维数组,使用index arrays相对简单。
import numpy as np
def slice_indices(some_list, some_slice):
"""Convert a slice into indices of a list"""
return np.arange(len(some_list))[some_slice]
# For a non-NumPy solution, use this:
# return range(*some_slice.indices(len(some_list)))
arr = np.arange(10)
# We'll make [1, 2, 3] and [8, 7] negative.
slice1, new1 = np.s_[1:4], [-1, -2, -3]
slice2, new2 = np.s_[8:6:-1], [-8, -7]
# (Here, np.s_ is just a nicer notation for slices.[1])
# Get indices to replace
idx1 = slice_indices(arr, slice1)
idx2 = slice_indices(arr, slice2)
# Use index arrays to assign to all of the indices
arr[[*idx1, *idx2]] = *new1, *new2
# That line expands to this:
arr[[1, 2, 3, 8, 7]] = -1, -2, -3, -8, -7
请注意,这并不能完全避免 Python 迭代——星号运算符仍然创建迭代器,索引数组是一个常规的 Python 列表。在有大量数据的情况下,这可能比手动方法慢得多,因为它会计算将分配的每个索引。
您还需要确保替换数据已经是正确的形状,或者您可以使用 NumPy 的手动广播功能(例如np.broadcast_to)来修复形状。这会带来额外的开销——如果您依赖自动广播,您最好在循环中执行分配。
arr = np.zeros(100)
idx1 = slice_indices(arr, slice(2, 5))
idx2 = slice_indices(arr, slice(12, 29))
new1 = np.broadcast_to(42, len(idx1))
new2 = np.broadcast_to(55, len(idx2))
arr[*idx1, *idx2] = *new1, *new2
为了推广到更多维度,slice_indices 需要注意形状,并且您必须更加小心地连接多组索引(而不是arr[[i1, i2, i3]],您需要arr[[i1, i2, i3], [j1, j2, j3]],不能直接连接)。
实际上,如果您经常需要这样做,最好使用一个简单的函数来封装您要避免的循环。
def set_slices(arr, *indices_and_values):
"""Set multiple locations in an array to their corresponding values.
indices_and_values should be a list of index-value pairs.
"""
for idx, val in indices_and_values:
arr[idx] = val
# Your example:
arr = np.zeros(100)
set_slices(arr, (np.s_[2:5], 42), (np.s_[12:29], 55))
(如果您的唯一目标是看起来就像您同时使用多个索引,here 是两个尝试为您做所有事情的函数,包括广播和处理多维数组。)
1np.s_