Подтвердить что ты не робот

Получайте одно и то же значение хэша для 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

Но моя цель - сохранить одно и то же значение хэша для фрейма данных во всех запусках приложений, чтобы получить некоторое значение из кеша.

4b9b3361

Ответ 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()