#python #arrays #numpy #for-loop
#питон #массивы #numpy #for-цикл
Вопрос:
Ввод: существует два входных массива:
value_array = [56, 10, 65, 37, 29, 14, 97, 46]
index_array = [ 0, 0, 1, 0, 3, 0, 1, 1]
Вывод: я хочу разделить value_array
использование index_array
без использования for-loop. Таким образом, выходной массив будет:
split_array = [[56, 10, 37, 14], # index 0
[65, 97, 46], # index 1
[], # index 2
[29]] # index 3
Есть ли какой-либо способ сделать это, используя numpy
без использования какого-либо for-цикла? Я посмотрел numpy.where
, но не могу понять, как это сделать.
For-loop: Вот способ сделать это с помощью for-loop. Я хочу избежать цикла for.
split_array = []
for i in range(max(index_array) 1):
split_array.append([])
for i in range(len(value_array)):
split_array[index_array[i]].append(value_array[i])
Комментарии:
1. У вас есть рабочая версия с циклом ?
2. @ivan добавил код с for-loop.
3. Поскольку
split_array
это список с массивами / списками различной длины, вы не можете избежать циклов уровня Python (даже если он скрыт вnp.split
функции).no-loop
Операции fabelled ограничены целым массивом (или фрагментами) и возвращают целые (числовые) массивы, а не списки списков.
Ответ №1:
Достаточно ли этого?
Решение 1 (Примечание: цикл for выполняется не по всему индексному массиву)
import numpy as np
value_array = np.array([56, 10, 65, 37, 29, 14, 97, 46])
index_array = np.array([ 0, 0, 1, 0, 3, 0, 1, 1])
max_idx = np.max(index_array)
split_array = []
for idx in range(max_idx 1):
split_array.append([])
split_array[-1].extend(list(value_array[np.where(index_array == idx)]))
print(split_array)
[[56, 10, 37, 14], [65, 97, 46], [], [29]]
Решение 2
import numpy as np
value_array = np.array([56, 10, 65, 37, 29, 14, 97, 46])
index_array = np.array([ 0, 0, 1, 0, 3, 0, 1, 1])
value_array = value_array[index_array.argsort()]
split_idxs = np.squeeze(np.argwhere(np.diff(np.sort(index_array)) != 0) 1)
print(np.array_split(value_array, split_idxs))
[array([56, 10, 37, 14]), array([65, 97, 46]), array([29])]
Комментарии:
1. Обновил мой вопрос. Я просто хочу избежать for-loop, воспользовавшись
numpy
. Редактировать: я заметил, что в вашем коде есть for-loop сmax_idx
итерацией, вместоlen(value_array)
чего это хорошо.2. Результатом второго решения является отсутствие пустого массива, не так ли?
Ответ №2:
Действительно, вы можете использовать numpy, используя массивы :
import numpy as np
value_array=np.array(value_array)
index_array=np.array(index_array)
split_array=[value_array[np.where(index_array==j)[0]] for j in set(index_array)]
Ответ №3:
Вы могли бы сделать:
import numpy as np
value_array = np.array([56, 10, 65, 37, 29, 14, 97, 46])
index_array = np.array([ 0, 0, 1, 0, 3, 0, 1, 1])
# find the unique values in index array and the corresponding counts
unique, counts = np.unique(index_array, return_counts=True)
# create an array with 0 for the missing indices
zeros = np.zeros(index_array.max() 1, dtype=np.int32)
zeros[unique] = counts # zeros = [4 3 0 1] 0 -> 4, 1 -> 3, 2 -> 0, 3 -> 1
# group by index array
so = value_array[np.argsort(index_array)] # so = [56 10 37 14 65 97 46 29]
# finally split using the counts
res = np.split(so, zeros.cumsum()[:-1])
print(res)
Вывод
[array([56, 10, 37, 14]), array([65, 97, 46]), array([], dtype=int64), array([29])]
Временная сложность этого подхода составляет O (N logN).
Кроме того, если вас не волнуют отсутствующие индексы, вы можете использовать следующее:
_, counts = np.unique(index_array, return_counts=True)
res = np.split(value_array[np.argsort(index_array)], counts.cumsum()[:-1])
print(res)
Вывод
[array([56, 10, 37, 14]), array([65, 97, 46]), array([29])]
Комментарии:
1.
np.split
циклические циклы — один фрагмент для каждого возвращаемого массива в списке.2. @hpaulj Полезно знать!