2009-04-30 15 views
25

Vorrei calcolare un hash di una classe Python contenente un set di dati per Machine Learning. L'hash è pensato per essere utilizzato per il caching, quindi stavo pensando a md5 o sha1. Il problema è che la maggior parte dei dati è archiviata in array NumPy; questi non forniscono un membro __hash__(). Attualmente eseguo uno pickle.dumps() per ogni membro e calcola un hash basato su queste stringhe. Tuttavia, ho trovato i seguenti link che indica che lo stesso oggetto potrebbe portare a diverse stringhe di serializzazione:Come hash un oggetto di grandi dimensioni (set di dati) in Python?

quale sarebbe il metodo migliore per calcolare un hash per una classe Python contenenti gli array Numpy?

+0

Non molto di un programmatore di python esperto, ma serializzerebbe l'oggetto e l'hashing che funzionano? – Louis

risposta

3

Qual è il formato dei dati negli array? Non potresti semplicemente scorrere gli array, convertirli in una stringa (tramite alcuni mezzi riproducibili) e poi inserirli nell'hash tramite l'aggiornamento?

ad es.

import hashlib 
m = hashlib.md5() # or sha1 etc 
for value in array: # array contains the data 
    m.update(str(value)) 

Non dimenticare però che gli array NumPy non fornirà __hash__() perché sono mutabili. Quindi fai attenzione a non modificare gli array dopo aver calcolato il tuo hash (in quanto non sarà più lo stesso).

+0

Grazie, il tuo post mi ha aiutato a risolvere questo problema. Vedi sotto ... –

27

Grazie a John Montgomery penso che ho trovato una soluzione, e penso che abbia meno overhead di convertire ogni numero possibilmente enormi array di stringhe:

posso creare un byte-vista delle matrici e usali per aggiornare l'hash. E in qualche modo questo sembra dare lo stesso digest come direttamente l'aggiornamento utilizzando la matrice:

>>> import hashlib 
>>> import numpy 
>>> a = numpy.random.rand(10, 100) 
>>> b = a.view(numpy.uint8) 
>>> print a.dtype, b.dtype # a and b have a different data type 
float64 uint8 
>>> hashlib.sha1(a).hexdigest() # byte view sha1 
'794de7b1316b38d989a9040e6e26b9256ca3b5eb' 
>>> hashlib.sha1(b).hexdigest() # array sha1 
'794de7b1316b38d989a9040e6e26b9256ca3b5eb' 
+0

Riuscirai a ricreare l'oggetto dalla cache con questa tecnica? Sembra che sarai in grado di ottenere una serie di tipo uint8 (sacrificando la precisione nell'array). – tgray

+0

Utilizzando la soluzione di John Montgomery, sembra che si otterrà un array float64. – tgray

+0

@tgray: A volte non importa tanto quanto la precisione. I dati sperimentali, soprattutto quelli di grandi dimensioni, tendono comunque ad avere grandi incertezze. Ovviamente questo è soggetto al contesto, ma la regola generale è che la doppia precisione è importante per il calcolo, non per memorizzare i dati o la risposta finale. –

1

array.data è sempre hashable, perché è un oggetto buffer. facile :) (a meno che non ti interessi la differenza tra matrici di forma diversa con gli stessi identici dati, ecc. (cioè questo è adatto a meno che forma, byteorder e altri parametri dell'array debbano figurare anche nell'hash)

+1

array.data non è lavabile a partire da numpy 1.6.2 e python 2.7 – yoavram

2

Ecco come lo faccio in jug (HEAD git al momento questa risposta):.

e = some_array_object 
M = hashlib.md5() 
M.update('np.ndarray') 
M.update(pickle.dumps(e.dtype)) 
M.update(pickle.dumps(e.shape)) 
try: 
    buffer = e.data 
    M.update(buffer) 
except: 
    M.update(e.copy().data) 

la ragione è che e.data è disponibile solo per alcuni array (array contigui) Stessa cosa con a.view(np.uint8) (che non riesce con un errore di tipo non descrittivo se l'array non è contiguo.

3

There I s un pacchetto per memoizzare le funzioni che usano array numpy come input joblib. Trovato dalla domanda this.

1

più veloce da un certo margine sembra essere:

hash (ITER (un))

a è un ndarray NumPy.

Ovviamente non sicuro hash, ma dovrebbe essere buono per la memorizzazione nella cache, ecc

+0

Sotto python 3.3+ non si otterranno gli stessi valori hash sulle diverse esecuzioni di python, a causa di miglioramenti della sicurezza. – xioxox

1

Utilizzando Numpy 1.10.1 e pitone 2.7.6, ora è possibile semplicemente hash array NumPy utilizzando hashlib se la matrice è C-contigua (utilizzare numpy.ascontiguousarray() in caso contrario, ad es

>>> h = hashlib.md5() 
>>> arr = numpy.arange(101) 
>>> h.update(arr) 
>>> print(h.hexdigest()) 
e62b430ff0f714181a18ea1a821b0918 
Problemi correlati