Лучший способ создать массив NumPy из словаря? - PullRequest
8 голосов
/ 02 марта 2009

Я только начинаю с NumPy, поэтому я могу упустить некоторые основные понятия ...

Какой лучший способ создать массив NumPy из словаря, значения которого являются списками?

Примерно так:

d = { 1: [10,20,30] , 2: [50,60], 3: [100,200,300,400,500] }

должно превратиться во что-то вроде:

data = [
  [10,20,30,?,?],
  [50,60,?,?,?],
  [100,200,300,400,500]
]

Я собираюсь сделать некоторые основные статистические данные для каждой строки, например:

deviations = numpy.std(data, axis=1)

Вопросы:

  • Какой самый лучший / самый эффективный способ создать массив numpy.array из словаря? Словарь большой; пара миллионов ключей, каждый с ~ 20 предметами.

  • Количество значений для каждой «строки» различно. Если я правильно понимаю, numpy хочет одинакового размера, так что я должен заполнить для пропущенных элементов, чтобы сделать std () счастливым?

Обновление: одну вещь, которую я забыл упомянуть, - хотя методы python разумны (например, быстрое выполнение нескольких миллионов элементов), он ограничен одним процессором. Numpy-операции хорошо масштабируются до аппаратного обеспечения и поражают все процессоры, поэтому они привлекательны.

Ответы [ 3 ]

8 голосов
/ 02 марта 2009

Вам не нужно создавать массивы numpy для вызова numpy.std (). Вы можете вызвать numpy.std () в цикле для всех значений вашего словаря. Список будет на лету преобразован в пустой массив для вычисления стандартного варианта.

Недостатком этого метода является то, что основной цикл будет в Python, а не в C. Но я думаю, что это должно быть достаточно быстро: вы все равно будете вычислять std на скорости C, и вы сэкономите много памяти, как вы не нужно хранить 0 значений, если у вас есть массивы переменного размера.

  • Если вы хотите еще больше оптимизировать это, вы можете сохранить свои значения в списке массивов numpy, чтобы вы выполняли преобразование списка python -> numpy array только один раз.
  • если вы обнаружите, что это все еще слишком медленно, попробуйте использовать psycho для оптимизации цикла python.
  • если это все еще слишком медленно, попробуйте использовать Cython вместе с модулем numpy. В этом учебном пособии заявлены впечатляющие улучшения скорости обработки изображений. Или просто запрограммируйте всю функцию std на Cython (см. this для тестов и примеров с функцией sum)
  • Альтернативой Cython будет использование SWIG с numpy.i .
  • если вы хотите использовать только numpy и рассчитать все на уровне C, попробуйте сгруппировать все записи одинакового размера в разные массивы и вызвать numpy.std () для каждого из них. Это должно выглядеть как в следующем примере.

пример со сложностью O (N):

import numpy
list_size_1 = []
list_size_2 = []
for row in data.itervalues():
    if len(row) == 1:
      list_size_1.append(row)
    elif len(row) == 2:
      list_size_2.append(row)
list_size_1 = numpy.array(list_size_1)
list_size_2 = numpy.array(list_size_2)
std_1 = numpy.std(list_size_1, axis = 1)
std_2 = numpy.std(list_size_2, axis = 1)
2 голосов
/ 02 марта 2009

Хотя здесь уже есть несколько довольно разумных идей, я считаю, что стоит упомянуть следующее.

Заполнение пропущенных данных любым значением по умолчанию испортит статистические характеристики (стандартное и т. Д.). Очевидно, именно поэтому Mapad предложил хороший трюк с группировкой записей одинакового размера. Проблема с этим (при условии, что нет никаких априорных данных о длине записей под рукой) состоит в том, что он требует даже больше вычислений, чем простое решение:

  1. не менее O (N * logN) * ​​1007 * 'len' вызовов и сравнений для сортировки с эффективным алгоритмом
  2. O (N) проверяет второй путь по списку для получения групп (их начальный и конечный индексы на «вертикальной» оси)

Использование Psyco - хорошая идея (поразительно проста в использовании, поэтому обязательно попробуйте).

Похоже, что оптимальным способом является использование стратегии, описанной Mapad в пуле № 1, но с модификацией - не для генерации всего списка, а для перебора словаря, преобразования каждой строки в numpy.array и выполнения необходимых вычислений. , Как это:

for row in data.itervalues():
    np_row = numpy.array(row)    
    this_row_std = numpy.std(np_row)
    # compute any other statistic descriptors needed and then save to some list

В любом случае несколько миллионов циклов в python не займут столько времени, сколько можно было ожидать. Кроме того, это не похоже на обычное вычисление, поэтому кого это волнует, если потребуется дополнительная секунда / минута, если оно запускается время от времени или хотя бы один раз.


Обобщенный вариант того, что было предложено Mapad:

from numpy import array, mean, std

def get_statistical_descriptors(a):
    if ax = len(shape(a))-1
    functions = [mean, std]
    return f(a, axis = ax) for f in functions


def process_long_list_stats(data):
    import numpy

    groups = {}

    for key, row in data.iteritems():
        size = len(row)
        try:
            groups[size].append(key)
        except KeyError:
            groups[size] = ([key])

    results = []

    for gr_keys in groups.itervalues():             
        gr_rows = numpy.array([data[k] for k in gr_keys])       
        stats = get_statistical_descriptors(gr_rows)                
        results.extend( zip(gr_keys, zip(*stats)) )

    return dict(results)
0 голосов
/ 24 июля 2012

numpy словарь

Вы можете использовать структурированный массив, чтобы сохранить возможность обращаться к пустому объекту с помощью ключа, например словаря.

import numpy as np


dd = {'a':1,'b':2,'c':3}
dtype = eval('[' + ','.join(["('%s', float)" % key for key in dd.keys()]) + ']')
values = [tuple(dd.values())]
numpy_dict = np.array(values, dtype=dtype)

numpy_dict['c']

теперь будет выводить

array([ 3.])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...