Как заполнить словарь из двух связанных массивов NumPy - альтернатива добавлению - PullRequest
0 голосов
/ 29 июня 2018

Я пытаюсь научиться использовать массивы NP вместо списков. Однако я изо всех сил пытаюсь определить правильный способ добавления значений в массив Numpy, когда все значения, принадлежащие массиву NP, неизвестны при его первоначальном создании.

Ниже приведен упрощенный пример того, как выглядел мой предыдущий код, где я добавляю значения в список в зависимости от того, к какой категории (в данном примере это страна) относятся значения. Таким образом, 3-е значение в списке значений принадлежит 3-й стране в списке стран (230 принадлежит Франции).

country = ['Germany','USA','France','Germany','USA','USA']
values = [250,220,230,180,180,220]

cv = {'Germany':[],'USA':[],'France':[]}

for i in range(len(country)):
    cv[country[i]].append(values[i])

Это упрощенный пример, и в действительности мне нужно добавить значения, которые намного длиннее, и, следовательно, я хотел бы знать, как наиболее эффективно переписать код, чтобы в итоге получился пустой массив вместо списков .

Ответы [ 3 ]

0 голосов
/ 29 июня 2018

Вы также можете использовать numpy.hstack().

import numpy as np

country = ['Germany','USA','France','Germany','USA','USA']
values = [250,220,230,180,180,220]

d={}

for c, v in zip(country, values):
    tmp_vec = np.array([v])
    try:
        d[c] = np.hstack((d[c],tmp_vec))
    except KeyError: #first occurence of this country
        d[c] = tmp_vec

оператор try: except: KeyError позволяет обрабатывать первый раз, когда обрабатывается ключ страны. В этом случае используется однозначный вектор, во всех остальных случаях используется hstack().

Имейте в виду, что hstack() возвращает копию и может не работать с большим объемом данных.

0 голосов
/ 29 июня 2018

Самый быстрый способ для больших массивов - использовать логическое маскирование .

Сначала добавим начальные списки в массивы NumPy:

countries = ['Germany','USA','France','Germany','USA','USA']
values = [250,220,230,180,180,220]
countries = np.array(countries)
values = np.array(values)

А теперь для каждой уникальной страны заполняем значения результирующего дикта cv сразу без добавления:

cv = {country: values[countries == country]
      for country in set(countries)}
print(cv)

даст:

{'France': array([230]),
 'USA': array([220, 180, 220]),
 'Germany': array([250, 180])}

Тайминги:

Я увеличил размеры массивов для более наглядного примера:

n = 500
countries = np.array(['Germany','USA','France','Germany','USA','USA'] * n)
values = np.array([250,220,230,180,180,220] * n)

# My version
%%timeit
cv = {country: values[countries == country]
      for country in set(countries)}
# 987 µs ± 5.46 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# MathiasRa's version
%%timeit
cv = {'Germany':[],'USA':[],'France':[]}
for i in range(len(countries)):
    cv[countries[i]].append(values[i])
# 1.67 ms ± 9.94 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# jpp's version
%%timeit
d = defaultdict(list)
for c, v in zip(countries, values):
    d[c].append(v)
res = {k: np.array(v) for k, v in d.items()}
# 1.5 ms ± 2.37 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# Johann Bzh's version
%%timeit
d={}
for c, v in zip(countries, values):
    tmp_vec = np.array([v])
    try:
        d[c] = np.hstack((d[c],tmp_vec))
    except KeyError: #first occurence of this country
        d[c] = tmp_vec  
# 13.3 ms ± 125 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
0 голосов
/ 29 июня 2018

np.append это зло. Это не преувеличение. Массивы NumPy лучше всего использовать, когда вы можете выделить память заранее. Именно здесь вступают в игру преимущества производительности от векторизованных операций.

С вашими данными лучше использовать list.append в цикле, используя defaultdict. Затем преобразуйте в NumPy через словарь.

from collections import defaultdict

country = ['Germany','USA','France','Germany','USA','USA']
values = [250,220,230,180,180,220]

d = defaultdict(list)

for c, v in zip(country, values):
    d[c].append(v)

res = {k: np.array(v) for k, v in d.items()}

print(res)

{'France': array([230]),
 'Germany': array([250, 180]),
 'USA': array([220, 180, 220])}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...