Pregunta

Estoy empezando con NumPy, por lo que me pueden faltar algunos conceptos básicos ...

¿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] }

Debería convertirse en algo 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 forma mejor / más eficiente de crear el numpy.array desde el 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, así que, ¿qué debo hacer para completar los elementos que faltan para hacer feliz a std ()?

Actualización: una cosa que olvidé mencionar, si bien las técnicas de Python son razonables (por ejemplo, hacer un bucle en unos pocos millones de elementos es rápido), está limitado a una sola CPU. Las operaciones numpy se adaptan bien al hardware y afectan a todas las CPU, por lo que son atractivas.

¿Fue útil?

Solución

No es necesario 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 computarás std a velocidad C, y ahorrarás mucha memoria a medida que no tendrá que almacenar 0 valores donde tenga matrices de tamaño variable.

  • Si desea optimizar aún más esto, puede almacenar sus valores en una lista de arrays numpy, de modo que haga la lista de python - > conversión de matriz numpy sólo una vez.
  • si encuentra que esto sigue siendo demasiado lento, intente usar psycho para optimizar el bucle de python.
  • si esto sigue siendo demasiado lento, intente usar Cython junto con el módulo numpy. Este Tutorial reclama mejoras de velocidad impresionantes para el procesamiento de imágenes. O simplemente programe la función estándar en Cython (vea esto para puntos de referencia y ejemplos con función de suma)
  • Una alternativa a Cython sería utilizar SWIG con numpy.i .
  • si desea usar solo numpy y hacer que todo se calcule a nivel C, intente agrupar todos los registros del mismo tamaño en diferentes arreglos y llame a numpy.std () en cada uno de ellos. Debería verse como el siguiente ejemplo.

ejemplo con complejidad 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)

Otros consejos

Aunque ya hay algunas ideas bastante razonables aquí presentes, creo que vale la pena mencionar las siguientes.

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

  1. al menos O (N * logN) 'len' llamadas y comparaciones para clasificar con un algoritmo efectivo
  2. O (N) comprueba la segunda forma de la lista para obtener grupos (sus índices de inicio y final en el eje 'vertical')

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

Parece que la forma óptima es tomar la estrategia descrita por Mapad en la viñeta # 1, pero con una modificación, no generar la lista completa, sino iterar a través del diccionario convirtiendo cada fila en numpy.array y realizando los cálculos necesarios . Así:

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 tomarán el tiempo que uno podría esperar. Además, esto no parece un cálculo de rutina, así que a quién le importa si toma segundos / minutos adicionales si se ejecuta de vez en cuando o solo una vez.


Una variante generalizada de lo 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)

diccionario numpy

Puedes usar una matriz estructurada para preservar la capacidad de abordar un objeto numpy mediante 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 saldrá

array([ 3.])
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top