Cara menyimpan kerangka data menggunakan Pandas

317

Saat ini saya mengimpor CSVframe data yang cukup besar setiap kali saya menjalankan skrip. Apakah ada solusi yang baik untuk menjaga agar frame data selalu tersedia di sela-sela proses jadi saya tidak perlu menghabiskan waktu menunggu skrip dijalankan?

jeffstern
sumber
2
Ya, ini adalah salah satu keluhan utama saya menggunakan Python - tidak ada cara sederhana untuk menyimpan & mengambil bingkai data. R dan SAS jauh lebih ramah pengguna dalam hal ini.
RobertF

Jawaban:

481

Cara termudah adalah dengan acar menggunakan to_pickle:

df.to_pickle(file_name)  # where to save it, usually as a .pkl

Kemudian Anda dapat memuatnya kembali menggunakan:

df = pd.read_pickle(file_name)

Catatan: sebelum 0.11.1 savedan loadmerupakan satu-satunya cara untuk melakukan ini (sekarang tidak digunakan lagi to_pickledan read_picklemasing - masing).


Pilihan populer lainnya adalah menggunakan HDF5 ( pytables ) yang menawarkan waktu akses sangat cepat untuk kumpulan data besar:

store = HDFStore('store.h5')

store['df'] = df  # save it
store['df']  # load it

Strategi yang lebih maju dibahas dalam buku masak .


Sejak 0.13 ada juga msgpack yang mungkin lebih baik untuk interoperabilitas, sebagai alternatif yang lebih cepat untuk JSON, atau jika Anda memiliki data objek python / teks-berat (lihat pertanyaan ini ).

Andy Hayden
sumber
8
@geekazoid save tidak lagi digunakan untuk to_pickle (yang membuat acar daripada csv, yang jauh lebih cepat / objek berbeda).
Andy Hayden
9
@geekazoid Jika data perlu diubah setelah memuat (yaitu string / objek ke datetime64) ini perlu dilakukan lagi setelah memuat csv yang disimpan, yang mengakibatkan hilangnya kinerja. acar menyimpan kerangka data dalam keadaan saat ini sehingga data dan formatnya dipertahankan. Ini dapat menyebabkan peningkatan kinerja besar-besaran.
harbun
4
Acar dan HDFStore tidak dapat menyimpan bingkai data lebih dari 8GB. Apakah ada alternatif?
user1700890
1
@ user1700890 cobalah untuk menghasilkan dari data acak (teks dan array) dan memposting pertanyaan baru. Saya tidak berpikir ini benar / curiga kami kehilangan sesuatu. Pertanyaan baru akan mendapatkan lebih banyak mata, tetapi cobalah untuk memasukkan / menghasilkan DataFrame yang mereproduksi :)
Andy Hayden
1
@YixingLiu Anda dapat mengubah mode setelah fakta stackoverflow.com/a/16249655/1240268
Andy Hayden
100

Meskipun sudah ada beberapa jawaban, saya menemukan perbandingan yang bagus di mana mereka mencoba beberapa cara untuk membuat serial Pandas DataFrames: Efisien Menyimpan Pandas DataFrames .

Mereka membandingkan:

  • acar: format data ASCII asli
  • cPickle, pustaka C.
  • pickle-p2: menggunakan format biner yang lebih baru
  • json: library jlib standardlib
  • json-no-index: seperti json, tetapi tanpa indeks
  • msgpack: alternatif JSON biner
  • CSV
  • hdfstore: format penyimpanan HDF5

Dalam percobaan mereka, mereka membuat serial DataFrame dari 1.000.000 baris dengan dua kolom diuji secara terpisah: satu dengan data teks, yang lain dengan angka. Penafian mereka mengatakan:

Anda tidak boleh percaya bahwa yang berikut digeneralisasikan ke data Anda. Anda harus melihat data Anda sendiri dan menjalankan benchmark sendiri

Kode sumber untuk tes yang mereka rujuk tersedia online . Karena kode ini tidak berfungsi secara langsung, saya membuat beberapa perubahan kecil, yang bisa Anda dapatkan di sini: serialize.py Saya mendapat hasil berikut:

hasil perbandingan waktu

Mereka juga menyebutkan bahwa dengan konversi data teks ke data kategorisasi , serialisasi menjadi jauh lebih cepat. Dalam pengujian mereka sekitar 10 kali lebih cepat (lihat juga kode tes).

Sunting : Waktu acar yang lebih tinggi daripada CSV dapat dijelaskan dengan format data yang digunakan. Secara default picklemenggunakan representasi ASCII yang dapat dicetak, yang menghasilkan set data yang lebih besar. Seperti yang dapat dilihat dari grafik, acar menggunakan format data biner yang lebih baru (versi 2, pickle-p2) memiliki waktu muat yang jauh lebih rendah.

Beberapa referensi lain:

agold
sumber
1
Saya memperbarui jawaban saya untuk menjelaskan pertanyaan Anda. Untuk meringkas: secara default acar menyimpan data dalam format ASCII.
lama
1
Ah, terima kasih untuk penjelasan itu! Sebagai catatan, panda DataFrame .to_pickle tampaknya menggunakan pkl.HIGHEST_PROTOCOL (harus 2)
ntg
2
Tampaknya blog yang ditautkan di atas ( Efisien Menyimpan Pandas DataFrames telah dihapus. Saya melakukan perbandingan sendiri dengan .to_pickle()(yang menggunakan penyimpanan biner) terhadap .to_hdf()(tanpa kompresi). Tujuannya adalah kecepatan, ukuran file untuk HDF adalah Acar 11x, dan waktu untuk memuat adalah 5x Pickle. Data saya ~ 5 k file ~ 7r baris x 6 cols masing-masing, sebagian besar numerik.
hamx0r
1
Halaman masih ada, Anda hanya perlu menghapus garis miring: Efisien Simpan Pandas DataFrames
IanSR
2
@ Mike Williamson, dalam pengujian saya, acar 5x lebih cepat untuk memuat daripada HDF dan juga mengambil 1/11 ruang disk (yaitu hdf 11x lebih besar pada disk dan mengambil 5x lebih banyak waktu untuk memuat dari disk seperti acar lakukan). ini semua di python 3 dengan panda 0.22.0.
hamx0r
35

Jika saya mengerti dengan benar, Anda sudah menggunakan pandas.read_csv()tetapi ingin mempercepat proses pengembangan sehingga Anda tidak perlu memuat file setiap kali Anda mengedit skrip Anda, apakah itu benar? Saya punya beberapa rekomendasi:

  1. Anda dapat memuat hanya bagian dari file CSV yang digunakan pandas.read_csv(..., nrows=1000)untuk hanya memuat sedikit bagian atas tabel, saat Anda melakukan pengembangan

  2. gunakan ipython untuk sesi interaktif, sehingga Anda menyimpan tabel panda dalam memori saat Anda mengedit dan memuat ulang skrip Anda.

  3. mengkonversi csv ke tabel HDF5

  4. penggunaan yang diperbaruiDataFrame.to_feather() dan pd.read_feather()untuk menyimpan data dalam format biner bulu yang kompatibel dengan R yang super cepat (di tangan saya, sedikit lebih cepat dari pandas.to_pickle()pada data numerik dan lebih cepat pada data string).

Anda mungkin juga tertarik dengan jawaban ini di stackoverflow.

Nuh
sumber
Apakah Anda tahu mengapa to_featherakan bekerja dengan baik pada data string? Saya membandingkan to_pickledan to_featurepada kerangka data numerik saya dan acar sekitar 3x lebih cepat.
zyxue
@zyxue pertanyaan yang bagus, jujur ​​saya belum banyak bermain dengan hal-hal bulu, jadi saya tidak punya jawaban
Noah
20

Acar bekerja dengan baik!

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
Anbarasu Ramachandran
sumber
8
Perhatikan bahwa file yang dihasilkan bukan file csv, mungkin lebih baik menggunakan ekstensi .pklseperti yang disarankan dalam jawaban @Andy Haydens.
Agold
5

Anda dapat menggunakan file format bulu. Ini sangat cepat.

df.to_feather('filename.ft')
Huanyu Liao
sumber
Dan data kemudian dapat digunakan secara langsung dengan Rmenggunakan featherperpustakaan.
James Hirschorn
4

Pandas DataFrames memiliki to_picklefungsi yang berguna untuk menyimpan 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
mgoldwasser
sumber
4

Seperti yang telah disebutkan ada berbagai opsi dan format file ( HDF5 , JSON , CSV , parket , SQL ) untuk menyimpan bingkai data. Namun, picklebukan warga negara kelas satu (tergantung pengaturan Anda), karena:

  1. pickleadalah risiko keamanan potensial. Bentuk dokumentasi Python untuk acar :

Peringatan tersebut picklemodul tidak aman terhadap data yang salah atau jahat dibangun. Jangan pernah menghapus data yang diterima dari sumber yang tidak dipercaya atau tidak terauthentikasi.

  1. picklelambat. Temukan tolok ukur di sini dan di sini .

Tergantung pada pengaturan Anda / penggunaan kedua keterbatasan tidak berlaku, tetapi saya tidak akan merekomendasikan picklesebagai kegigihan default untuk bingkai data panda.

Michael Dorner
sumber
1

Format file numpy cukup cepat untuk data numerik

Saya lebih suka menggunakan file numpy karena cepat dan mudah digunakan. Berikut ini adalah patokan sederhana untuk menyimpan dan memuat bingkai data dengan 1 kolom 1 juta poin.

import numpy as np
import pandas as pd

num_dict = {'voltage': np.random.rand(1000000)}
num_df = pd.DataFrame(num_dict)

menggunakan %%timeitfungsi ajaib ipython

%%timeit
with open('num.npy', 'wb') as np_file:
    np.save(np_file, num_df)

outputnya adalah

100 loops, best of 3: 5.97 ms per loop

untuk memuat data kembali ke dalam kerangka data

%%timeit
with open('num.npy', 'rb') as np_file:
    data = np.load(np_file)

data_df = pd.DataFrame(data)

outputnya adalah

100 loops, best of 3: 5.12 ms per loop

TIDAK BURUK!

Kon

Ada masalah jika Anda menyimpan file numpy menggunakan python 2 dan kemudian coba buka menggunakan python 3 (atau sebaliknya).

tandai jay
sumber
6
perhatikan bahwa solusi ini akan menghapus semua nama kolom Anda dan mengubah semua data integer Anda menjadi float :(
Joseph Garvin
0

https://docs.python.org/3/library/pickle.html

Format protokol acar:

Protokol versi 0 adalah protokol “terbaca oleh manusia” asli dan kompatibel dengan versi Python sebelumnya.

Protokol versi 1 adalah format biner lama yang juga kompatibel dengan versi Python sebelumnya.

Protokol versi 2 diperkenalkan dengan Python 2.3. Ini memberikan pengawetan kelas gaya baru yang jauh lebih efisien. Lihat PEP 307 untuk informasi tentang perbaikan yang dibawa oleh protokol 2.

Protokol versi 3 ditambahkan dalam Python 3.0. Ini memiliki dukungan eksplisit untuk objek byte dan tidak dapat dihapuskan dengan Python 2.x. Ini adalah protokol default, dan protokol yang direkomendasikan ketika kompatibilitas dengan versi Python 3 lainnya diperlukan.

Protokol versi 4 ditambahkan dalam Python 3.4. Ini menambahkan dukungan untuk objek yang sangat besar, pengawetan lebih banyak jenis objek, dan beberapa optimasi format data. Lihat PEP 3154 untuk informasi tentang perbaikan yang dibawa oleh protokol 4.

Gilco
sumber
0

kompatibilitas pyarrow lintas versi

Langkah keseluruhan adalah ke pyarrow / feather (peringatan penghentian dari panda / msgpack). Namun saya memiliki tantangan dengan pyarrow dengan transient dalam spesifikasi Data bersambung dengan pyarrow 0.15.1 tidak dapat di-deserialized dengan 0.16.0 ARROW-7961 . Saya menggunakan serialisasi untuk menggunakan redis jadi harus menggunakan pengkodean biner.

Saya telah menguji ulang berbagai opsi (menggunakan notebook jupyter)

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")

Dengan hasil berikut untuk bingkai data saya (dalam outvariabel 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>
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=

bulu dan parket tidak berfungsi untuk bingkai data saya. Saya akan terus menggunakan pyarrow. Namun saya akan melengkapi dengan acar (tanpa kompresi). Saat menulis ke cache, simpan pyarrow dan acar formulir bersambung. Saat membaca dari cadangan mundur untuk acar jika deserialisation pyarrow gagal.

Rob Raymond
sumber
Ini tidak menjawab pertanyaan
Jason S
0

Formatnya tergantung pada kasus penggunaan Anda

  • Simpan DataFrame di antara sesi notebook - bulu , jika Anda terbiasa acar - juga ok.
  • Simpan DataFrame dalam ukuran file sekecil mungkin - parket atau pickle.gz (periksa apa yang lebih baik untuk data Anda)
  • Simpan DataFrame yang sangat besar (10+ jutaan baris) - hdf
  • Dapat membaca data di platform lain (bukan Python) yang tidak mendukung format lain - csv , csv.gz , periksa apakah parket didukung
  • Dapat meninjau dengan mata Anda / menggunakan Excel / Google Sheets / Git diff - csv
  • Simpan DataFrame yang mengambil hampir semua RAM - csv

Perbandingan format file panda ada di video ini .

artoby
sumber