Domanda

Sto iniziando con NumPy, quindi potrei mancare alcuni concetti chiave ...

Qual è il modo migliore per creare un array NumPy da un dizionario i cui valori sono elenchi?

Qualcosa del genere:

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

Dovrebbe trasformarsi in qualcosa del tipo:

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

Farò alcune statistiche di base su ogni riga, ad esempio:

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

Domande:

  • Qual è il modo migliore / più efficiente per creare numpy.array dal dizionario? Il dizionario è grande; un paio di milioni di chiavi, ciascuna con ~ 20 elementi.

  • Il numero di valori per ogni 'riga' sono diversi. Se capisco correttamente che numpy vuole una dimensione uniforme, quindi cosa devo compilare affinché gli elementi mancanti rendano felice std ()?

Aggiornamento: una cosa che ho dimenticato di menzionare - mentre le tecniche di Python sono ragionevoli (ad es. il looping su alcuni milioni di elementi è veloce), è vincolato a una singola CPU. Le operazioni di Numpy si adattano perfettamente all'hardware e colpiscono tutte le CPU, quindi sono attraenti.

È stato utile?

Soluzione

Non è necessario creare array numpy per chiamare numpy.std (). Puoi chiamare numpy.std () in un ciclo su tutti i valori del tuo dizionario. L'elenco verrà convertito al volo in una matrice numpy al volo per calcolare la variazione standard.

Il rovescio della medaglia di questo metodo è che il ciclo principale sarà in pitone e non in C. Ma suppongo che questo dovrebbe essere abbastanza veloce: calcolerai comunque std a velocità C e risparmierai molta memoria mentre non sarà necessario memorizzare 0 valori in cui sono presenti matrici di dimensioni variabili.

  • Se vuoi ottimizzare ulteriormente questo, puoi archiviare i tuoi valori in un elenco di matrici numpy, in modo da fare la lista di Python - > conversione numpy dell'array solo una volta.
  • se trovi che è ancora troppo lento, prova a usare psycho per ottimizzare il loop di Python.
  • se è ancora troppo lento, prova a utilizzare Cython insieme al modulo numpy. Questo Tutorial afferma notevoli miglioramenti della velocità per l'elaborazione delle immagini. O semplicemente programma l'intera funzione std in Cython (vedi this per benchmark ed esempi con funzione di somma)
  • Un'alternativa a Cython sarebbe usare SWIG con numpy.i .
  • se vuoi usare solo numpy e hai tutto calcolato a livello C, prova a raggruppare tutti i record della stessa dimensione insieme in array diversi e chiama numpy.std () su ciascuno di essi. Dovrebbe apparire come nell'esempio seguente.

esempio con complessità 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)

Altri suggerimenti

Mentre ci sono già alcune idee abbastanza ragionevoli qui presenti, credo che vale la pena menzionare quanto segue.

Riempire i dati mancanti con qualsiasi valore predefinito rovinerebbe le caratteristiche statistiche (standard, ecc.). Evidentemente è per questo che Mapad ha proposto il bel trucco con il raggruppamento di dischi delle stesse dimensioni. Il problema con esso (supponendo che non ci siano dati a priori sulle lunghezze dei record) è che coinvolge ancora più calcoli rispetto alla soluzione semplice:

  1. almeno O (N * logN) chiamate "len" e confronti per l'ordinamento con un algoritmo efficace
  2. O (N) controlla il secondo modo attraverso l'elenco per ottenere gruppi (i loro indici di inizio e fine sull'asse "verticale")

L'uso di Psyco è una buona idea (è sorprendentemente facile da usare, quindi assicurati di provarlo).

Sembra che il modo ottimale sia prendere la strategia descritta da Mapad nel punto 1, ma con una modifica - non generare l'intero elenco, ma scorrere il dizionario convertendo ogni riga in numpy.array ed eseguendo i calcoli richiesti . In questo modo:

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

In ogni caso alcuni milioni di loop in Python non impiegheranno il tempo che ci si potrebbe aspettare. Inoltre questo non sembra un calcolo di routine, quindi chi se ne frega se impiega un secondo / minuto in più se viene eseguito una volta ogni tanto o anche solo una volta.


Una variante generalizzata di ciò che è stato suggerito da 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)

dizionario intorpidito

Puoi usare un array strutturato per preservare la capacità di indirizzare un oggetto intorpidito da una chiave, come un dizionario.

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

verrà ora visualizzato

array([ 3.])
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top