Зараз я імпортую досить великий CSV
як кадр даних щоразу, коли запускаю сценарій. Чи є хороше рішення для постійного доступу до цього фрейму даних між прогонами, тому мені не доведеться витрачати весь цей час на очікування запуску сценарію?
Зараз я імпортую досить великий CSV
як кадр даних щоразу, коли запускаю сценарій. Чи є хороше рішення для постійного доступу до цього фрейму даних між прогонами, тому мені не доведеться витрачати весь цей час на очікування запуску сценарію?
Відповіді:
Найпростіший спосіб - маринувати його, використовуючи to_pickle
:
df.to_pickle(file_name) # where to save it, usually as a .pkl
Потім ви можете завантажити його назад, використовуючи:
df = pd.read_pickle(file_name)
Примітка: раніше 0.11.1 save
і це load
був єдиний спосіб зробити це (тепер вони застаріли на користь to_pickle
і read_pickle
відповідно).
Ще одним популярним вибором є використання HDF5 ( піблетів ), який пропонує дуже швидкий час доступу для великих наборів даних:
store = HDFStore('store.h5')
store['df'] = df # save it
store['df'] # load it
Більш прогресивні стратегії обговорюються в кулінарній книзі .
Оскільки 0,13 є також msgpack, який може бути кращим для сумісності, як більш швидка альтернатива JSON, або якщо у вас є дані з об'єкта / важкого тексту (див. Це питання ).
Хоча вже є кілька відповідей, я знайшов приємне порівняння, в якому вони спробували декілька способів серіалізувати Pandas DataFrames: Ефективно зберігати DataFrames Pandas .
Вони порівнюють:
У своєму експерименті вони серіалізують DataFrame в 1 000 000 рядків з двома тестовими стовпцями: один з текстовими даними, а другий з цифрами. Їх застереження говорить:
Вам не слід вірити, що наступне узагальнює ваші дані. Ви повинні самі переглянути свої дані та запустити орієнтири
Вихідний код тесту, на який вони посилаються, доступний в Інтернеті . Оскільки цей код не працював безпосередньо, я внесла деякі незначні зміни, які ви можете отримати тут: serialize.py, я отримав такі результати:
Вони також зазначають, що з перетворенням текстових даних у категоричні дані серіалізація відбувається значно швидше. У їх тесті приблизно 10 разів швидше (також дивіться код тесту).
Редагувати : Більш високий час для соління, ніж CSV, можна пояснити використовуваним форматом даних. За замовчуванням pickle
використовується друкуване представлення ASCII, яке генерує більші набори даних. Як видно з графіку, соління, використовуючи новіший формат бінарних даних (версія 2, pickle-p2
), має набагато менший час завантаження.
Деякі інші посилання:
numpy.fromfile
найшвидше..to_pickle()
(який використовує двійкове сховище) проти .to_hdf()
(без стиснення). Мета - швидкість, розмір файлу для HDF - 11x Pickle, і час завантаження був 5x Pickle. Мої дані складали ~ 5k файлів ~ 7k рядків x 6 cols кожен, в основному числовий.
Якщо я правильно розумію, ви вже використовуєте, pandas.read_csv()
але хотіли б прискорити процес розробки, щоб вам не довелося завантажувати файл щоразу, коли ви редагували сценарій, це правильно? У мене є кілька рекомендацій:
ви можете завантажити лише частину файлу CSV, використовуючи pandas.read_csv(..., nrows=1000)
лише для завантаження верхнього біта таблиці, поки ви займаєтеся розробкою
використовуйте ipython для інтерактивного сеансу, щоб зберегти таблицю панд у пам'яті під час редагування та перезавантаження сценарію.
конвертувати CSV в таблицю HDF5
оновлено використання DataFrame.to_feather()
і pd.read_feather()
для зберігання даних в R-сумісного перо довічного формату , який дуже швидко (в моїх руках, трохи швидше , ніж pandas.to_pickle()
на числових даних і набагато швидше на рядки даних).
Вас також може зацікавити ця відповідь про stackoverflow.
to_feather
б добре працювати над рядковими даними? Я зробив орієнтир, to_pickle
і to_feature
на моєму числовому фреймі даних і маринований набір приблизно в 3 рази швидший.
Соління добре працює!
import pandas as pd
df.to_pickle('123.pkl') #to save the dataframe, df to 123.pkl
df1 = pd.read_pickle('123.pkl') #to load 123.pkl back to the dataframe df
.pkl
як запропоновано у відповіді @Andy Haydens.
Ви можете використовувати файл формату перо. Це надзвичайно швидко.
df.to_feather('filename.ft')
R
допомогою feather
бібліотеки.
Панди DataFrames мають to_pickle
функцію, яка корисна для збереження DataFrame:
import pandas as pd
a = pd.DataFrame({'A':[0,1,0,1,0],'B':[True, True, False, False, False]})
print a
# A B
# 0 0 True
# 1 1 True
# 2 0 False
# 3 1 False
# 4 0 False
a.to_pickle('my_file.pkl')
b = pd.read_pickle('my_file.pkl')
print b
# A B
# 0 0 True
# 1 1 True
# 2 0 False
# 3 1 False
# 4 0 False
Як вже було сказано , для зберігання кадру даних існують різні варіанти та формати файлів ( HDF5 , JSON , CSV , паркет , SQL ). Однак pickle
це не першокласний громадянин (залежно від вашого налаштування), оскільки:
pickle
є потенційним ризиком для безпеки. Сформувати документацію Python для розсолу :Попередження В
pickle
модулі не захищене від помилкових або зловмисно побудованих даних. Ніколи не зніміть дані, отримані від недовіреного або несанкціонованого джерела.
Залежно від вашого налаштування / використання обидва обмеження не застосовуються, але я б не рекомендував pickle
зберігати кадри даних панд за замовчуванням.
Я вважаю за краще використовувати нудні файли, оскільки з ними швидко і просто працювати. Ось простий орієнтир для збереження та завантаження фрейму даних з 1 стовпцем в 1 мільйон точок.
import numpy as np
import pandas as pd
num_dict = {'voltage': np.random.rand(1000000)}
num_df = pd.DataFrame(num_dict)
використовуючи %%timeit
магічну функцію ipython
%%timeit
with open('num.npy', 'wb') as np_file:
np.save(np_file, num_df)
вихід є
100 loops, best of 3: 5.97 ms per loop
щоб завантажити дані назад у кадр даних
%%timeit
with open('num.npy', 'rb') as np_file:
data = np.load(np_file)
data_df = pd.DataFrame(data)
вихід є
100 loops, best of 3: 5.12 ms per loop
НЕПОГАНО!
Виникла проблема, якщо ви збережете файл numpy за допомогою python 2, а потім спробуйте відкрити за допомогою python 3 (або навпаки).
https://docs.python.org/3/library/pickle.html
Формати протоколу соління:
Версія 0 протоколу є оригінальним "читабельним для людини" протоколом і назад сумісна з більш ранніми версіями Python.
Версія 1 протоколу - це старий двійковий формат, який також сумісний з більш ранніми версіями Python.
Версія 2 протоколу була введена в Python 2.3. Це забезпечує набагато ефективніший маринування класів нового стилю. Зверніться до PEP 307 для інформації про покращення, внесені протоколом 2.
Версія 3 протоколу була додана в Python 3.0. Він має явну підтримку байтових об'єктів і не може бути відібраний Python 2.x. Це протокол за замовчуванням, і рекомендований протокол, коли потрібна сумісність з іншими версіями Python 3.
Версія 4 протоколу була додана в Python 3.4. Він додає підтримку дуже великих об'єктів, збирання більшої кількості об'єктів, а також деякі оптимізації формату даних. Зверніться до PEP 3154 для інформації про покращення, внесені протоколом 4.
Загальний крок був спрямований на голову / перо (попередження про депрекацію від панд / msgpack). Однак у мене є завдання з головоломкою з перехідними в специфікації Дані, серіалізовані з пірроу 0,15.1, не можна десеріалізувати за допомогою 0,16,0 СТРІК -7961 . Я використовую серіалізацію для використання redis, тому доводиться використовувати двійкове кодування.
Я повторно перевіряв різні варіанти (використовуючи ноутбук "Юпітер")
import sys, pickle, zlib, warnings, io
class foocls:
def pyarrow(out): return pa.serialize(out).to_buffer().to_pybytes()
def msgpack(out): return out.to_msgpack()
def pickle(out): return pickle.dumps(out)
def feather(out): return out.to_feather(io.BytesIO())
def parquet(out): return out.to_parquet(io.BytesIO())
warnings.filterwarnings("ignore")
for c in foocls.__dict__.values():
sbreak = True
try:
c(out)
print(c.__name__, "before serialization", sys.getsizeof(out))
print(c.__name__, sys.getsizeof(c(out)))
%timeit -n 50 c(out)
print(c.__name__, "zlib", sys.getsizeof(zlib.compress(c(out))))
%timeit -n 50 zlib.compress(c(out))
except TypeError as e:
if "not callable" in str(e): sbreak = False
else: raise
except (ValueError) as e: print(c.__name__, "ERROR", e)
finally:
if sbreak: print("=+=" * 30)
warnings.filterwarnings("default")
З наступними результатами для мого кадру даних (у out
змінній jupyter)
pyarrow before serialization 533366
pyarrow 120805
1.03 ms ± 43.9 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pyarrow zlib 20517
2.78 ms ± 81.8 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
msgpack before serialization 533366
msgpack 109039
1.74 ms ± 72.8 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
msgpack zlib 16639
3.05 ms ± 71.7 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
pickle before serialization 533366
pickle 142121
733 µs ± 38.3 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pickle zlib 29477
3.81 ms ± 60.4 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
feather ERROR feather does not support serializing a non-default index for the index; you can .reset_index() to make the index into column(s)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
parquet ERROR Nested column branch had multiple children: struct<x: double, y: double>
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
пір'я та паркет не працюють для моєї кадри даних. Я продовжую використовувати пірроу. Однак я доповнимо солінням (без компресії). Під час запису в кеш зберігають серіализовані форми пірроу і маринованих солінь. Під час читання з кеш-пам’яті резервне підсолювання, якщо деріаріалізація пірра не виходить.
Формат залежить від Вашого випадку використання
Порівняння форматів файлів панди є у цьому відео .