Pandalar kullanarak veri çerçevesi nasıl saklanır


317

Şu anda CSVher komut dosyasını çalıştırdığımda veri çerçevesi olarak oldukça büyük bir içe aktarıyorum . Senaryo çalıştırmak için bekleyen bu veri çerçevesi sürekli kullanılabilir tutmak için iyi bir çözüm var, bu yüzden komut dosyası çalıştırmak için bekleyen tüm zaman harcamak gerekmez?


2
Evet, bu Python kullanarak yaptığım en büyük şikayetlerimden biri - veri çerçevelerini kaydetmenin ve almanın basit bir yolu yok. R ve SAS bu açıdan çok daha kullanıcı dostudur.
RobertF

Yanıtlar:


481

En kolay yol onu kullanarak turşu yapmaktırto_pickle :

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

Ardından aşağıdakileri kullanarak geri yükleyebilirsiniz:

df = pd.read_pickle(file_name)

Not: 0.11.1'den önce saveve loadbunu yapmanın tek yolu vardı (şimdi sırasıyla to_pickleve lehine reddedildi read_pickle).


Bir başka popüler bir seçim kullanmaktır HDF5 ( pytables sunar) çok hızlı büyük veri setleri için erişim süreleri:

store = HDFStore('store.h5')

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

Daha ileri stratejiler yemek kitabında tartışılmıştır .


0.13'ten beri , birlikte çalışabilirlik için daha iyi olabilecek, JSON'a daha hızlı bir alternatif olarak veya python nesnesi / metin ağırlıklı verileriniz varsa msgpack de vardır ( bu soruya bakın ).


8
@geekazoid save, to_pickle'a (çok daha hızlı / farklı bir nesne olan bir csv yerine bir turşu oluşturur) kaldırılır.
Andy Hayden

9
@geekazoid Verilerin yüklendikten sonra dönüştürülmesi gerektiğinde (örneğin, dize / nesne datetime64'e), kaydedilen bir csv yüklendikten sonra tekrar yapılması gerekir, bu da performans kaybına neden olur. turşu veri çerçevesini geçerli durumuna kaydeder, böylece veriler ve biçimi korunur. Bu, büyük performans artışlarına yol açabilir.
harbun

4
Hem turşu hem de HDFStore, veri karesini 8 GB'den fazla kaydedemez. Alternatif var mı?
user1700890

1
@ user1700890 rastgele verilerden (metin ve diziler) oluşturmaya ve yeni bir soru yayınlamaya çalışın. Bunun doğru olabileceğini sanmıyorum / bir şeyleri kaçırdığımızdan şüpheleniyorum. Yeni soru daha fazla göz alacak, ancak çoğaltan bir DataFrame eklemeye / oluşturmaya çalışın :)
Andy Hayden


100

Zaten bazı cevaplar olmasına rağmen ben Pandalar DataFrames serileştirmek için çeşitli yollar denedim güzel bir karşılaştırma buldum: Verimli Pandas DataFrames depolamak .

Karşılaştırırlar:

  • turşu: orijinal ASCII veri formatı
  • cPickle, bir C kütüphanesi
  • pickle-p2: daha yeni ikili biçimi kullanır
  • json: standardlib json kütüphanesi
  • json-no-index: json gibi, ancak dizinsiz
  • msgpack: ikili JSON alternatifi
  • CSV
  • hdfstore: HDF5 depolama biçimi

Denemelerinde, ayrı ayrı test edilen iki sütunla 1.000.000 satırlık bir DataFrame'i serilerler: biri metin verileriyle, diğeri sayılarla. Sorumluluk reddi beyanları:

Aşağıdaki bilgilerin verileriniz için genelleştirildiğine güvenmemelisiniz. Kendi verilerinize bakmalı ve karşılaştırmaları kendiniz çalıştırmalısınız

Başvurdukları testin kaynak kodu çevrimiçi olarak mevcuttur . Bu kod doğrudan çalışmadığından, burada alabilirsiniz bazı küçük değişiklikler yaptım: serialize.py Aşağıdaki sonuçları aldım:

zaman karşılaştırma sonuçları

Ayrıca metin verilerinin kategorik verilere dönüştürülmesiyle serileştirmenin çok daha hızlı olduğunu belirtiyorlar . Testlerinde yaklaşık 10 kat daha hızlı (ayrıca test koduna bakın).

Düzenleme : Turşu için CSV'den daha yüksek süreler kullanılan veri formatı ile açıklanabilir. Varsayılan olarak pickle, daha büyük veri setleri oluşturan yazdırılabilir bir ASCII temsili kullanır. Ancak grafikte görülebileceği gibi, daha yeni ikili veri formatını (sürüm 2 pickle-p2) kullanan turşu çok daha düşük yükleme sürelerine sahiptir.

Diğer bazı referanslar:


1
Sorunuzu açıklamak için cevabımı güncelledim. Özetlemek gerekirse: turşu varsayılan olarak verileri ASCII formatında saklar.
agold

1
Ah, bu açıklama için teşekkürler! Not olarak, pandalar DataFrame .to_pickle, pkl.HIGHEST_PROTOCOL (2 olmalı) kullanıyor gibi görünüyor
ntg

2
Yukarıda bağlantılı blog görünüyor ( Verimli Mağaza Pandas DataFrames silindi. Karşılıklı.to_pickle() (ikili depolama kullanan) kendi karşılaştırmaları yaptım .to_hdf()(sıkıştırma olmadan) .. Amaç hız, HDF için dosya boyutu 11x Turşu ve yükleme zamanı Verilerim ~ 7k satır x her biri 6 sütun olmak üzere ~ 5k dosya, çoğunlukla sayısal.
hamx0r

1
Sayfa hala var, sadece sondaki eğik çizgiyi kaldırmanız gerekiyor: Pandas DataFrames
IanSR

2
@Mike Williamson, testimde, turşunun yüklenmesi HDF'den 5 kat daha hızlıydı ve ayrıca disk alanının 1 / 11'ini aldı (yani hdf diskte 11x daha büyüktü ve turşu gibi diskten yüklemek için 5 kat daha fazla zaman aldı). bunların hepsi pandalar 0.22.0 ile python 3'teydi.
hamx0r

35

Doğru anlıyorsam, zaten kullanıyorsunuz pandas.read_csv()ancak geliştirme sürecinizi hızlandırmak istiyorsunuz, böylece komut dosyanızı her düzenlediğinizde dosyayı yüklemenize gerek yok, doğru mu? Birkaç tavsiyem var:

  1. CSV dosyasının yalnızca bir kısmını pandas.read_csv(..., nrows=1000), geliştirme yaparken tablonun yalnızca üst bitini yüklemek için kullanarak yükleyebilirsiniz.

  2. Komut dosyanızı düzenleyip yeniden yüklerken pandalar tablosunu bellekte tutacak şekilde etkileşimli bir oturum için ipython kullanın .

  3. csv'yi HDF5 tablosuna dönüştürme

  4. güncellenmiş kullanım DataFrame.to_feather()ve pd.read_feather()verileri süper hızlı olan R uyumlu tüy ikili biçiminde saklamak (ellerimde, pandas.to_pickle()sayısal verilere göre biraz daha hızlı ve dize verilerinde çok daha hızlı).

Stackoverflow'daki bu yanıta da ilgi duyabilirsiniz.


to_featherDize verilerinde neden iyi sonuç vereceğini biliyor musunuz ? Ben benchmarked to_pickleve to_featurebenim sayısal dataframe ve turşu daha hızlı 3x ilgili.
zyxue

@zyxue iyi soru, dürüstçe tüy şeylerle çok oynamadım, bu yüzden bir cevabım yok
Noah

20

Turşu iyi çalışıyor!

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

8
Oluşturulan dosyaların csv dosyaları olmadığını unutmayın, belki .pkl@Andy Haydens yanıtında önerildiği gibi uzantıyı kullanmak daha iyidir .
2015'te

5

Geçiş yumuşatma dosyası kullanabilirsiniz. Son derece hızlı.

df.to_feather('filename.ft')

Ve veriler daha sonra doğrudan kullanılabilir Rkullanarak featherkütüphane.
James Hirschorn

4

Panda DataFrames to_picklebir DataFrame kaydetmek için yararlı bir işleve sahiptir:

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

4

Daha önce de belirtildiği gibi , bir veri çerçevesini saklamak için farklı seçenekler ve dosya formatları ( HDF5 , JSON , CSV , parke , SQL ) vardır. Ancak, picklebirinci sınıf bir vatandaş değildir (kurulumunuza bağlı olarak), çünkü:

  1. picklepotansiyel bir güvenlik riskidir. Turşu için Python belgelerini oluşturun :

Uyarıpickle modülü hatalı veya kötü niyetle oluşturulmuş veri karşı güvenli değildir. Güvenilmeyen veya kimliği doğrulanmamış bir kaynaktan alınan verileri hiçbir zaman seçmeyin.

  1. pickleyavaş. Burada ve burada karşılaştırmalar bulun .

Kurulum / kullanımınıza bağlı olarak her iki sınırlama geçerli değildir, ancak picklepanda veri çerçeveleri için varsayılan kalıcılık olarak tavsiye etmem .


1

Sayısal dosya formatları sayısal veriler için oldukça hızlıdır

Hızlı ve kullanımı kolay oldukları için numpy dosyaları kullanmayı tercih ederim. İşte 1 sütun 1 milyon puanlık bir veri çerçevesini kaydetmek ve yüklemek için basit bir karşılaştırma.

import numpy as np
import pandas as pd

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

ipython'un %%timeitsihirli işlevini kullanarak

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

çıktı

100 loops, best of 3: 5.97 ms per loop

verileri bir veri çerçevesine geri yüklemek için

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

data_df = pd.DataFrame(data)

çıktı

100 loops, best of 3: 5.12 ms per loop

FENA DEĞİL!

EKSİLERİ

Numpy dosyasını python 2 kullanarak kaydedip python 3 kullanarak açmayı denerseniz (veya tersi) bir sorun vardır.


6
bu çözümün tüm sütun adlarınızı sildiğini ve tüm tamsayı verilerinizi yüzecek şekilde değiştireceğini unutmayın :(
Joseph Garvin

0

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

Turşu protokolü formatları:

Protokol sürüm 0, orijinal "insan tarafından okunabilir" protokolüdür ve Python'un önceki sürümleriyle geriye dönük olarak uyumludur.

Protokol sürüm 1, Python'un önceki sürümleriyle de uyumlu eski bir ikili biçimdir.

Protokol sürüm 2, Python 2.3'te tanıtıldı. Yeni stil sınıflarının çok daha verimli bir şekilde temizlenmesini sağlar. Protokol 2'nin getirdiği iyileştirmeler hakkında bilgi için PEP 307'ye bakınız.

Protokol sürüm 3, Python 3.0'a eklendi. Bayt nesneleri için açık bir desteği vardır ve Python 2.x tarafından seçilemez. Bu varsayılan protokoldür ve diğer Python 3 sürümleriyle uyumluluk gerektiğinde önerilen protokoldür.

Protokol sürüm 4, Python 3.4'e eklendi. Çok büyük nesneler için destek, daha fazla nesne türü ve bazı veri biçimi optimizasyonları ekler. Protokol 4 tarafından getirilen iyileştirmeler hakkında bilgi için PEP 3154'e bakınız.


0

versiyonlar arasında pyarrow uyumluluğu

Genel hamle pyarrow / geçiş yumuşatma olmuştur (pandalar / msgpack'ten kullanımdan kaldırma uyarıları). Ancak şartnamede geçici olan pyarrow ile bir sorunum var 0.15.1 pyarrow ile serileştirilmiş veriler 0.16.0 ARROW-7961 ile serileştirilemez . Ben bir ikili kodlama kullanmak zorunda redis kullanmak için serileştirme kullanıyorum.

Çeşitli seçenekleri tekrar test ettim (jupyter notebook kullanarak)

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

Veri çerçevem ​​için aşağıdaki sonuçlar ile ( outjupyter değişkeninde)

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>
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=

tüy ve parke benim veri çerçevem ​​için çalışmıyor. Ben silahı kullanmaya devam edeceğim. Ancak turşu ile takviye edeceğim (sıkıştırma yok). Önbellek deposuna yazarken pyarrow ve turşu serileştirilmiş formlar. Önbellek serileştirme başarısız olursa önbellek düşme turşu için okurken.


Bu soruya cevap vermiyor
Jason S

0

Biçim, kullanım durumunuza bağlıdır

  • DataFrame'i dizüstü bilgisayar oturumları arasında kaydedin - tüy , turşu yapmaya alışkınsanız - ayrıca tamam.
  • DataFrame'i mümkün olan en küçük dosya boyutunda kaydedin - parke veya pickle.gz (verileriniz için neyin daha iyi olduğunu kontrol edin)
  • Çok büyük bir DataFrame'i kaydedin (10+ milyon satır) - HDF
  • Diğer formatları desteklemeyen başka bir platformda (Python değil) verileri okuyabilmek - csv , csv.gz , parkenin desteklenip desteklenmediğini kontrol edin
  • Gözlerinizle yorum yapabilme / Excel / Google E-Tablolar / Git diff - csv kullanma
  • Neredeyse tüm RAM'i alan bir DataFrame'i kaydedin - CSV

Pandalar dosya biçimlerinin karşılaştırılması içindedir Bu videoda .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.