Получайте одно и то же значение хэша для Pandas DataFrame каждый раз
Моя цель - получить уникальное значение хэша для DataFrame. Я получаю его из CSV файла.
Весь смысл состоит в том, чтобы получить один и тот же хэш каждый раз, когда я вызываю hash() на нем.
Моя идея заключалась в том, что я создаю функцию
def _get_array_hash(arr):
arr_hashable = arr.values
arr_hashable.flags.writeable = False
hash_ = hash(arr_hashable.data)
return hash_
который вызывает базовый массив numpy, установите его в неизменяемое состояние и получите хэш из буфера.
INLINE UPD.
Начиная с 08.11.2016, эта версия функции больше не работает. Вместо этого вы должны использовать
hash(df.values.tobytes())
См. комментарии для Наиболее эффективное свойство хэша для массива numpy.
END OF INLINE UPD.
Он работает для обычного массива pandas:
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
Но потом я пытаюсь применить его к DataFrame, полученному из файла .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
Может кто-нибудь объяснить мне, как это возможно?
Я могу создать из него новый DataFrame, например
new_data = pd.DataFrame(data=data_from_file.values,
columns=data_from_file.columns,
index=data_from_file.index)
и он снова работает
In [25]: _get_array_hash(new_data)
Out[25]: -3546154109803008241
In [26]: _get_array_hash(new_data)
Out[26]: -3546154109803008241
Но моя цель - сохранить одно и то же значение хэша для фрейма данных во всех запусках приложений, чтобы получить некоторое значение из кеша.
Ответы
Ответ 1
Начиная с Pandas 0.20.1, вы можете использовать малоизвестный (и плохо документированный) hash_pandas_object
(исходный код), который недавно был опубликован в pandas.util
. Он возвращает одно хеш-значение для строки достижения кадра данных (и работает с сериями и т.д. Тоже)
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
Вы всегда можете сделать hash_pandas_object(df).sum()
если вам нужен общий хеш всех строк.
Ответ 2
У меня была аналогичная проблема: проверьте, изменен ли кадр данных, и я решил его путем хэширования строки сериализации msgpack. Это кажется стабильным среди разных перезагрузок одних и тех же данных.
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()