2015-07-22 9 views
11

Il mio obiettivo è ottenere un valore hash univoco per un DataFrame. Lo ottengo dal file .csv. Il punto intero è ottenere lo stesso hash ogni volta che chiamo hash() su di esso.Ottieni lo stesso valore di hash per un DataFrame Pandas ogni volta

La mia idea era che creo la funzione

def _get_array_hash(arr): 
    arr_hashable = arr.values 
    arr_hashable.flags.writeable = False 
    hash_ = hash(arr_hashable.data) 
    return hash_ 

che chiama sottostante matrice NumPy, impostato a condizione immutabile e ottenere hash del buffer.

INLINE UPD.

A partire dall'8.11.2016, questa versione della funzione non funziona più. Invece, è necessario utilizzare

hash(df.values.tobytes()) 

Vedere commenti per Most efficient property to hash for numpy array.

END DI INLINE UPD.

Si lavora per regolare array di panda:

In [12]: data = pd.DataFrame({'A': [0], 'B': [1]}) 

In [13]: _get_array_hash(data) 
Out[13]: -5522125492475424165 

In [14]: _get_array_hash(data) 
Out[14]: -5522125492475424165 

Ma poi cerco di applicarlo a dataframe ottenuto da un file .csv:

In [15]: fpath = 'foo/bar.csv' 

In [16]: data_from_file = pd.read_csv(fpath) 

In [17]: _get_array_hash(data_from_file) 
Out[17]: 6997017925422497085 

In [18]: _get_array_hash(data_from_file) 
Out[18]: -7524466731745902730 

Qualcuno può spiegare, come è quello possibile ?

posso creare nuova dataframe fuori di esso, come

new_data = pd.DataFrame(data=data_from_file.values, 
      columns=data_from_file.columns, 
      index=data_from_file.index) 

e funziona di nuovo

In [25]: _get_array_hash(new_data) 
Out[25]: -3546154109803008241 

In [26]: _get_array_hash(new_data) 
Out[26]: -3546154109803008241 

Ma il mio obiettivo è quello di preservare lo stesso valore di hash per un dataframe attraverso l'applicazione lancia in ordine per recuperare un valore dalla cache.

+1

Questo potrebbe aiutare: https://github.com/TomAugspurger/engarde/issues/3 –

+0

Ho provato l'approccio con ottenere il valore hash dell'indice e delle colonne e il valore di str (data_frame). È lento e soffre degli stessi problemi. – mkurnikov

+0

Anche io sono interessato a farlo - posso chiederti perché hai incluso "arr_hashable.flags.writeable = False"? Ti aspetteresti che la funzione hash() modifichi l'array altrimenti? –

risposta

4

Ho avuto un problema simile: verifica se un dataframe è stato modificato e l'ho risolto eseguendo l'hashing della stringa di serializzazione msgpack. Questo sembra stabile tra diversi ricaricando gli stessi dati.

import pandas as pd 
import hashlib 
DATA_FILE = 'data.json' 

data1 = pd.read_json(DATA_FILE) 
data2 = pd.read_json(DATA_FILE) 

assert hashlib.md5(data1.to_msgpack()).hexdigest() == hashlib.md5(data2.to_msgpack()).hexdigest() 
assert hashlib.md5(data1.values.tobytes()).hexdigest() != hashlib.md5(data2.values.tobytes()).hexdigest() 
+0

Ho trovato '.to_msgpack()' stable in Python 3.6 ma non in 3.5 (non so perché, potrebbe avere qualcosa a che fare con i dizionari ordinati in Python 3.6+). Basta tenerlo semplice e per '.to_csv(). Encode ('utf-8')' invece. – ostrokach

1

Come di panda 0.20.1, è possibile utilizzare il poco conosciuto (e scarsamente documentati) hash_pandas_object (source code), che è stato recentemente made public in pandas.utils. Esso restituisce un valore hash per fila distanza dal dataframe (e funziona su serie ecc troppo)

import pandas as pd 
import numpy as np 

np.random.seed(42) 
arr = np.random.choice(['foo', 'bar', 42], size=(3,4)) 
df = pd.DataFrame(arr) 

print(df) 
#  0 1 2 3 
# 0 42 foo 42 42 
# 1 foo foo 42 bar 
# 2 42 42 42 42 


from pandas.util import hash_pandas_object 
h = hash_pandas_object(df) 

print(h) 
# 0  5559921529589760079 
# 1 16825627446701693880 
# 2  7171023939017372657 
# dtype: uint64 

si può sempre fare hash_pandas_object(df).sum() se si vuole un hash complessiva di tutte le righe.

Problemi correlati