Не существует хорошего способа прямого извлечения нескольких фрагментов из массива NumPy, а тем более фрагментов разных размеров. Но вы можете обмануть, преобразовав свои срезы в индексы и используя массив индексов.
В случае одномерных массивов это относительно просто, используя индексные массивы .
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
) для исправления форм. Это приводит к дополнительным накладным расходам - если вы полагались на автоматическое вещание c, вам, вероятно, лучше выполнять назначения в al oop.
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]]
, который нельзя объединить напрямую).
На практике, если вам нужно много делать, вам, вероятно, лучше использовать простую функцию для инкапсуляции l oop, которого вы пытаетесь избежать.
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))
(Если Ваша единственная цель - сделать так, чтобы выглядело , как будто вы используете несколько индексов одновременно, здесь - это две функции, которые пытаются сделать все для вас, включая широковещательную передачу и обработку многомерных массивов.)
1 np.s_