Pergunta

Eu estou apenas começando com NumPy assim que eu pode estar faltando alguns conceitos básicos ...

Qual é a melhor maneira de criar uma matriz NumPy de um dicionário cujos valores são listas?

Algo parecido com isto:

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

Caso se transformar em algo como:

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

Eu vou fazer algumas estatísticas básicas sobre cada linha, por exemplo:

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

Perguntas:

  • O que é a melhor maneira / mais eficiente para criar o numpy.array do dicionário? O dicionário é grande; um par de milhões de chaves, cada uma com ~ 20 itens.

  • O número de valores para cada 'linha' são diferentes. Se eu entendi corretamente desejos numpy tamanho uniforme, então o que eu preencher para os itens em falta para fazer std () feliz?

Update: - (. Por exemplo, looping sobre alguns milhões de itens é rápido) Uma coisa que eu esqueci de mencionar, enquanto as técnicas python são razoáveis, é restrita a uma única CPU. operações Numpy escala muito bem para o hardware e bateu todos os CPUs, por isso eles são atraentes.

Foi útil?

Solução

Você não precisa criar matrizes numpy para numpy.std call (). Você pode chamar numpy.std () em um loop sobre todos os valores do seu dicionário. A lista será convertido para uma matriz numpy em tempo real para calcular a variação padrão.

A desvantagem deste método é que o loop principal será em python e não em C. Mas eu acho que isso deve ser rápido o suficiente: você ainda vai std computação na velocidade C, e você vai economizar uma grande quantidade de memória como você não terá que armazenar valores 0, onde você tem matrizes de tamanho variável.

  • Se você quiser otimizar ainda mais isso, você pode armazenar seus valores em uma lista de arrays numpy, de modo que você faz a lista de python -> conversão variedade numpy apenas uma vez.
  • Se você achar que isso ainda é muito lento, tente usar psico para otimizar o loop python.
  • se isso ainda é muito lento, tente usar Cython em conjunto com o módulo numpy. Este Tutorial afirma melhorias de velocidade impressionantes para processamento de imagem. Ou simplesmente programar toda a função std em Cython (ver este para benchmarks e exemplos com função soma)
  • Uma alternativa para Cython seria usar SWIG com numpy.i .
  • Se você quiser usar apenas numpy e ter tudo calculado ao nível C, tente agrupar todos os registros de mesmo tamanho juntos em diferentes matrizes e numpy.std chamada () em cada um deles. Deve olhar como exemplo a seguir.

exemplo com O (N) complexidade:

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)

Outras dicas

Embora já existam algumas idéias bastante razoáveis ??apresentar aqui, eu creio que se segue é a pena mencionar.

Preencher dados em falta com qualquer valor padrão iria estragar as características estatísticas (STD, etc). Evidentemente, é por isso que Mapad propôs o truque agradável com o agrupamento mesmos registros porte. O problema com ele (assumindo que não há qualquer um dado a priori em comprimentos de registros está na mão) é que ele envolve ainda mais cálculos do que a solução simples:

  1. , pelo menos, O (N * logN) 'len' chamadas e comparações para classificar com um algoritmo efetivo
  2. O (N) verificações sobre o segundo caminho através da lista para se obter grupos (o seu início e índices finais no eixo 'vertical')

Usando Psyco é uma boa idéia (é surpreendentemente fácil de usar, por isso não deixe de dar-lhe uma tentativa).

Parece que o ideal maneira é tomar a estratégia descrita por Mapad na bala # 1, mas com uma modificação - não para gerar toda a lista, mas iterate através do dicionário convertendo cada linha em numpy.array e realizando cálculos necessários . Como esta:

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

Em qualquer caso alguns milhões de loops em python não vai demorar tanto quanto se poderia esperar. Além desta não se parece com um cálculo de rotina, então quem se importa se ele leva segundo extra / minuto, se ele é executado de vez em quando ou mesmo apenas uma vez.


A generalizada variante do que foi sugerido por 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)

numpy dicionário

Você pode usar uma matriz estruturada de forma a preservar a capacidade de lidar com um objeto numpy por uma chave, como um dicionário.

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']

irá agora de saída

array([ 3.])
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top