2009-03-02 17 views
8

Estoy comenzando con NumPy, así que me pueden faltar algunos conceptos básicos ...¿La mejor manera de crear una matriz NumPy a partir de un diccionario?

¿Cuál es la mejor manera de crear una matriz NumPy a partir de un diccionario cuyos valores son listas?

Algo como esto:

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

debe convertirse en algo así como:

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

Voy a hacer algunas estadísticas básicas en cada fila, por ejemplo:

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

Preguntas:

  • ¿Cuál es la mejor/más eficiente forma de crear el archivo numpy.array del diccionario? El diccionario es grande; un par de millones de claves, cada una con ~ 20 elementos.

  • El número de valores para cada 'fila' es diferente. Si entiendo correctamente numpy quiere un tamaño uniforme, entonces, ¿qué debo completar para los elementos faltantes para hacer feliz a std()?

Actualización: Una cosa que se olvidó de mencionar - mientras que las técnicas de pitón son razonables, está limitado a una sola CPU (por ejemplo, un bucle durante un par de millones de artículos es rápido.). Las operaciones numeradas se adaptan muy bien al hardware y afectan a todas las CPU, por lo que son atractivas.

Respuesta

8

No necesita crear matrices numpy para llamar a numpy.std(). Puede llamar a numpy.std() en un bucle sobre todos los valores de su diccionario. La lista se convertirá en una matriz numpy sobre la marcha para calcular la variación estándar.

La desventaja de este método es que el bucle principal estará en python y no en C. Pero supongo que esto debería ser lo suficientemente rápido: aún calculará std a velocidad C, y ahorrará mucha memoria como no tendrá que almacenar 0 valores donde tenga matrices de tamaño variable.

  • Si desea optimizar aún más esto, se puede almacenar sus valores en una lista de matrices numpy, de modo que lo hace la lista de Python -> numpy conversión array sólo una vez.
  • si ve que esto todavía es demasiado lento, intente usar psycho para optimizar el ciclo de python.
  • si esto todavía es demasiado lento, intente utilizar Cython junto con el módulo numpy. Este Tutorial afirma mejoras de velocidad impresionantes para el procesamiento de imágenes. O simplemente programe la función std completa en Cython (consulte this para pruebas comparativas y ejemplos con la función suma)
  • Una alternativa a Cython sería usar SWIG con numpy.i.
  • si desea usar solo numpy y tener todo calculado a nivel C, intente agrupar todos los registros del mismo tamaño en diferentes matrices y llame a numpy.std() en cada uno de ellos. Debería verse como el siguiente ejemplo.

ejemplo con O complejidad (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) 
+0

que estoy haciendo la numpy.std en un bucle ahora, y tienes razón, el ahorro de memoria son importantes. Sin embargo, me gustaría hacer al menos una comparación de velocidad con la versión numpy. – Parand

+0

El problema es que numpy.std() se creó para aceptar solo arreglo de arreglo de tamaño. Entonces, la única forma en que veo hacer esta prueba es agrupar todos los registros del mismo tamaño y llamar a numpy.std() en cada uno de ellos. – Mapad

+0

¿No debería ser realmente CPython Cython? ¿Lo he entendido mal? – batbrat

2

Si bien ya hay algunas ideas muy razonables presentes aquí, creo que sigue es digno de mención.

Rellenar los datos faltantes con cualquier valor predeterminado estropearía las características estadísticas (estándar, etc.). Evidentemente, es por eso que Mapad propuso el buen truco de agrupar registros del mismo tamaño. El problema con esto es que implica incluso más cálculos que la solución directa (suponiendo que no hay ningún dato a priori sobre los registros de longitudes está a la mano es):

  1. al menos O (N * logN) llamadas y comparaciones para la clasificación con un algoritmo eficaz
  2. O (N) controles sobre el segundo camino a través de la lista para obtener grupos (su principio y los índices de extremo en el eje 'vertical')
'len'

Usar Psyco es una buena idea (es sorprendentemente fácil de usar, así que asegúrate de probarlo).

Parece que la forma óptima es tomar la estrategia descrita por Mapad en la viñeta n.º 1, pero con una modificación: no generar la lista completa, sino iterar por el diccionario convirtiendo cada fila en numpy.array y realizar el trabajo requerido cómputos. De esta manera:

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 

En cualquier caso, unos pocos millones de bucles en python no tardarán tanto como cabría esperar. Además, esto no parece una computación de rutina, así que a quién le importa si se necesita un segundo/minuto extra si se ejecuta de vez en cuando o incluso una sola vez.


Una variante generalizada de lo que fue 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) 
+0

Gracias Maleev, esto es esencialmente lo que terminé haciendo. Una cosa que olvidé mencionar es que mientras bucle en Python es rápido, creo que solo estoy usando una sola CPU con este método. Las operaciones de matriz afectan a todas las CPU, por lo que son atractivas. – Parand

+0

¿Por qué debería ordenar las filas antes de agrupar vectores por longitud? Solo se necesita agrupar.Además, sería cuidadoso con la gran notación O: aquí N ~ 1000000 pero la velocidad entre un programa Python y C puede ser ~ 100 veces más lenta. Entonces N -> 1000 realmente no tiende al infinito – Mapad

+0

2 Parand: Tienes razón, tener en cuenta el multi-threading realmente tiene sentido. 2 Mapad: Si no estoy terriblemente equivocado, la agrupación es esencialmente equivalente a la clasificación. ¿Cómo sugieres agruparlos? – Maleev

0

diccionario numpy

Puede utilizar una matriz estructurada para preservar la capacidad para hacer frente a un objeto numpy por una clave como un diccionario

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

ahora la salida

array([ 3.]) 
+0

Sin embargo, la matriz resultante tiene una tupla anidada, por lo que podría ser más lenta para algunas operaciones. –

Cuestiones relacionadas