"Индикаторная" функция для элементов массива
Я сразу с примера того, что мне нужно.
Можно ли без циклов и map сделать из массива a = [3, 1, 3] два таких массива [[3, 0, 3], [0, 1, 0]]? Т. е. новый массив имеет размер (n, len(a)), где n - это число различных элементов в a. При этом строчки нового массива образуются так: одинаковые элементы остаются на своих местах, а на остальных местах взамен старых ставятся нули. Надеюсь понятно объяснил.
Например:
на входе массив: a = [3, 1, 2, 1, 3]
ожидаемый результат: [[3, 0, 0, 0, 3], [0, 1, 0, 1, 0], [0, 0, 2, 0, 0]].
Можно ли методами векторизации решить эту задачу?
Порядок получившихся строк не имеет значения. У меня практически нет идей. Допустим, я создал n нужных пустых массивов (допустим они состоят из нулей). А как дальше? Подскажите, пожалуйста.
Ответы (2 шт):
Полувекторизированное решение - цикл пробегает по уникальным значениям:
import numpy as np
import pandas as pd
a = np.array([3, 1, 2, 1, 3])
unq = pd.unique(a)
res = np.zeros((len(unq), len(a)), dtype="int32")
for i,n in enumerate(unq):
res[i][a == n] = n
результат:
In [265]: res
Out[265]:
array([[3, 0, 0, 0, 3],
[0, 1, 0, 1, 0],
[0, 0, 2, 0, 0]], dtype=int32)
Без циклов for:
import numpy as np
a = np.array([3, 1, 2, 1, 3])
n_a=a.shape[0] # число элементов в исходном массиве
unq=np.unique(a)
n_unq=unq.shape[0] # число уникальных элементов
b= np.tile(a, (n_unq, 1))
c=np.tile(unq, (n_a, 1)).T
print(c*(b==c))
или еще вариант:
import numpy as np
a = np.array([3, 1, 2, 1, 3])
unq=np.unique(a)
M=np.meshgrid(a, unq)
print(np.where(M[0]==M[1], M[0], 0))
Если массив большой, то, возможно, стоит использовать разреженные матрицы.