Замена записей массива NumPy их частотами / значениями из словаря
Проблема: из двух входных массивов я хочу вывести массив с частотой True значений (от input_2), соответствующих каждому значению input_1.
import numpy as np # import everything from numpy from scipy.stats import itemfreq input_1 = np.array([3,6,6,3,6,4]) input_2 = np.array([False, True, True, False, False, True])
Для этого примера вывод, который я хочу:
output_1 = np.array([0,2,2,0,2,1])
Мой текущий подход включает в себя редактирование input_1, поэтому остаются только значения, соответствующие True:
locs=np.where(input_2==True,input_1,0)
Затем подсчитывая частоту каждого ответа, создавая словарь и заменяя соответствующие клавиши ввода_1 на значения (истинные частоты).
loc_freq = itemfreq(locs) dic = {} for key,val in loc_freq: dic[key]=val print dic for k, v in dic.iteritems(): input_1[input_1==k]=v
который выводит [3,2,2,3,2,1].
Проблема здесь двоякая: 1) это все еще ничего не делает с ключами, которые не находятся в словаре (и поэтому их следует изменить на 0). Например, как я могу превратить 3s в 0s? 2) Это кажется очень неэффективным / неэффективным. Есть ли лучший способ приблизиться к этому?
- Множество массивов numpy с определенным форматом
- numpy.argmax: как получить индекс, соответствующий возникновению * последнего *, в случае множественных вхождений максимальных значений
- Python: как группировать список объектов по их характеристикам или атрибутам?
- Как «масштабировать» массив numpy?
- Как создать сетку композитных струн
np.bincount
– это то, что вы ищете.
output_1 = np.bincount(input_1[input_2])[input_1]
Решение @memecs правильно, +1. Однако он будет очень медленным и займет много памяти, если значения в input_1
действительно велики, то есть они не являются индексами массива, но говорят, что это секунды или некоторые другие целочисленные данные, которые могут принимать очень большие значения.
В этом случае у вас есть np.bincount(input_1[input_2]).size
равен наибольшему целому числу в input_1
с True
значением в input_2
.
Гораздо быстрее использовать unique
и bincount
. Мы используем первое, чтобы извлечь индексы уникальных элементов input_1
, а затем использовать bincount
для подсчета того, как часто эти индексы появляются в том же массиве и взвешивают их 1
или 0
на основе значения массива input_2
( True
или False
) :
# extract unique elements and the indices to reconstruct the array unq, idx = np.unique(input_1, return_inverse=True) # calculate the weighted frequencies of these indices freqs_idx = np.bincount(idx, weights=input_2) # reconstruct the array of frequencies of the elements frequencies = freqs_idx[idx] print(frequencies)
Это решение очень быстро и имеет минимальное влияние на память. Кредит отправляется на @Jaime, см. Его комментарий ниже. Ниже я сообщаю свой оригинальный ответ, используя unique
по-другому.
ДРУГИЕ ВОЗМОЖНОСТИ
Возможно, быстрее пойти на другое решение, используя unique
:
import numpy as np input_1 = np.array([3, 6, 6, 3, 6, 4]) input_2 = np.array([False, True, True, False, False, True]) non_zero_hits, counts = np.unique(input_1[input_2], return_counts=True) all_hits, idx = np.unique(input_1, return_inverse=True) frequencies = np.zeros_like(all_hits) #2nd step, with broadcasting idx_non_zero_hits_in_all_hits = np.where(non_zero_hits[:, np.newaxis] - all_hits == 0)[1] frequencies[idx_non_zero_hits_in_all_hits] = counts print(frequencies[idx])
Это имеет недостаток, который потребует большой памяти, если количество уникальных элементов в input_1
с True
значением в input_2
много, из-за созданного и переданного 2D-массива. Чтобы уменьшить объем памяти, вы можете использовать цикл for вместо второго шага алгоритма:
#2nd step, but with a for loop. for j, val in enumerate(non_zero_hits): index = np.where(val == all_hits)[0] frequencies[index] = counts[j] print(frequencies[idx])
Это второе решение имеет очень небольшой объем памяти, но требует цикла for
. Это зависит от вашего типичного размера ввода данных и значений, решение которых будет лучше всего.
Реализованное в настоящее время решение для бинтонов довольно элегантно, но пакет numpy_indexed обеспечивает более общие решения таких проблем:
import numpy_indexed as npi idx = npi.as_index(input_1) unique_labels, true_count_per_label = npi.group_by(idx).sum(input_2) print(true_count_per_label[idx.inverse])
- Результат вызова функции не является подходящим массивом поплавков. fsolve
- В чем разница между этими двумя способами для очистки списков?
- Как сохранить порядок позиций в словаре Python?
- RawArray из массива numpy?
- Что приводит к этим операциям индексации нарезки и эллипса?
- индекс печати numpy определенного значения
- Лучший способ инициализировать и заполнить массив numpy?
- numpy заменить элементы массива со средним числом 2 * 2 блоков
- Использование массивов с другими массивами в Python