Pandas를 사용하여 데이터 프레임을 저장하는 방법


317

지금 CSV은 스크립트를 실행할 때마다 상당히 큰 데이터 프레임을 가져 옵니다. 실행 사이에 데이터 프레임을 지속적으로 사용할 수있는 좋은 솔루션이 있습니까? 그래서 스크립트 실행을 기다리는 데 시간을 할애 할 필요가 없습니까?


2
그러나 이것은 Python을 사용하는 주요 불만 중 하나입니다. 데이터 프레임을 저장하고 검색하는 간단한 방법은 없습니다. R과 SAS는이 점에서 훨씬 사용자 친화적입니다.
RobertF

답변:


481

가장 쉬운 방법은 다음을 사용하여 피클 하는 것입니다 to_pickle.

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

그런 다음 다음을 사용하여 다시로드 할 수 있습니다.

df = pd.read_pickle(file_name)

참고 : 0.11.1 이전 saveload이 작업을 수행 할 수있는 유일한 방법 (그들은 지금의 찬성되지 않습니다했다 to_pickleread_pickle각각).


또 다른 대중적인 선택은 대용량 데이터 세트에 매우 빠른 액세스 시간을 제공 하는 HDF5 ( pytables ) 를 사용 하는 것입니다 .

store = HDFStore('store.h5')

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

더 고급 전략은 요리 책 에서 논의됩니다 .


0.13부터는 JSON보다 빠른 대안으로 또는 파이썬 객체 / 텍스트가 많은 데이터가있는 경우 상호 운용성을 위해 더 나은 msgpack 이 있습니다 ( 이 질문 참조 ).


8
@geekazoid save는 to_pickle에서 더 이상 사용되지 않습니다 (CSV가 아닌 피클을 생성하므로 훨씬 빠르고 다른 객체입니다).
Andy Hayden

9
@geekazoid로드 후 데이터를 변환해야하는 경우 (예 : 문자열 / 객체를 datetime64로) 변환 한 경우 저장된 csv를로드 한 후 다시 수행해야하므로 성능이 저하됩니다. pickle은 데이터 프레임을 현재 상태로 저장하므로 데이터와 형식이 유지됩니다. 이로 인해 성능이 크게 향상 될 수 있습니다.
harbun

4
pickle과 HDFStore는 모두 8GB 이상의 데이터 프레임을 저장할 수 없습니다. 대안이 있습니까?
user1700890

1
@ user1700890은 임의의 데이터 (텍스트 및 배열)에서 생성을 시도하고 새로운 질문을 게시합니다. 나는 이것이 옳지 않다고 생각합니다. 우리가 무언가를 놓친 것 같습니다. 새로운 질문은 더 많은 눈을 얻을 것이지만 다음을 재현하는 DataFrame을 포함 / 생성하려고 시도합니다.)
Andy Hayden

1
@YixingLiu 당신은 사실 후 모드를 변경할 수 있습니다 stackoverflow.com/a/16249655/1240268
Andy Hayden

100

이미 몇 가지 답변이 있지만 Pandas DataFrames를 효율적 으로 직렬화하는 여러 가지 방법을 시도한 훌륭한 비교를 발견했습니다. 효율적으로 Pandas DataFrames 저장하십시오 .

그들은 다음을 비교합니다.

  • 피클 : 원본 ASCII 데이터 형식
  • cPickle, C 라이브러리
  • pickle-p2 : 최신 이진 형식을 사용합니다
  • json : standardlib json 라이브러리
  • json-no-index : json과 비슷하지만 색인이 없습니다.
  • msgpack : 바이너리 JSON 대안
  • CSV
  • hdfstore : HDF5 저장 형식

실험에서 그들은 개별적으로 테스트 된 두 개의 열 (하나는 텍스트 데이터, 다른 하나는 숫자)로 1,000,000 행의 DataFrame을 직렬화합니다. 그들의 면책 조항은 다음과 같이 말합니다.

다음 내용이 데이터를 일반화한다고 믿지 않아야합니다. 자신의 데이터를보고 벤치 마크를 직접 실행해야합니다.

그들이 참조하는 테스트의 소스 코드는 온라인에서 볼 수 있습니다 . 이 코드가 직접 작동하지 않았기 때문에 약간의 변경 사항을 만들었습니다. serialize.py 다음과 같은 결과를 얻었습니다.

시간 비교 결과

또한 텍스트 데이터를 범주 형 데이터로 변환 하면 직렬화가 훨씬 빠릅니다. 테스트에서 약 10 배 정도 빠릅니다 (테스트 코드 참조).

편집 : CSV보다 피클에 더 많은 시간을 사용 된 데이터 형식으로 설명 할 수 있습니다. 기본적으로 pickle더 큰 데이터 세트를 생성하는 인쇄 가능한 ASCII 표현을 사용합니다. 그러나 그래프에서 볼 수 있듯이 최신 이진 데이터 형식 (버전 2, pickle-p2)을 사용하는 피클 은로드 시간이 훨씬 짧습니다.

다른 참고 문헌들 :


1
귀하의 질문을 설명하기 위해 답변을 업데이트했습니다. 요약하면 기본적으로 pickle은 ASCII 형식으로 데이터를 저장합니다.
agold

1
아, 그 설명 감사합니다! 참고로, pandas DataFrame .to_pickle은 pkl.HIGHEST_PROTOCOL (2이어야 함)을 사용하는 것으로 보입니다.
ntg

2
위에 링크 된 블로그 인 것 같습니다 ( 효율적으로 Store Pandas DataFrames 가 삭제되었습니다. 압축없이 .to_pickle())와 바이너리 바이너리를 사용하는 자체 비교를 .to_hdf()했습니다. 목표는 속도, HDF의 파일 크기는 11x Pickle,로드하는 시간이었습니다 5x Pickle. 내 데이터는 ~ 7k 행 x 6 열의 ~ 5k 파일 (주로 숫자)
hamx0r

1
: 페이지가 여전히 그냥 후행 슬래시 제거 할 필요가 존재 효율적으로 저장 팬더 DataFrames
IanSR

2
필자의 테스트에서 @Mike Williamson은 pickle이 HDF보다 5 배 더 빠르며 디스크 공간의 1/11을 차지했습니다 (즉, hdf는 디스크에서 11 배 더 크고 디스크에서로드하는 데 많은 시간이 걸렸습니다). 이것은 판다 0.22.0이있는 파이썬 3에 모두있었습니다.
hamx0r

35

내가 올바르게 이해하고 있다면 이미 사용하고 pandas.read_csv()있지만 스크립트를 편집 할 때마다 파일을로드 할 필요가 없도록 개발 프로세스를 가속화하고 싶습니다. 맞습니까? 몇 가지 권장 사항이 있습니다.

  1. pandas.read_csv(..., nrows=1000)개발하는 동안 테이블의 최상위 비트 만로드하는 데 사용하여 CSV 파일의 일부만로드 할 수 있습니다.

  2. 스크립트를 편집하고 다시로드 할 때 팬더 테이블을 메모리에 유지하도록 대화식 세션에 ipython 을 사용 하십시오.

  3. CSV를 HDF5 테이블 로 변환

  4. 업데이트 된 사용 DataFrame.to_feather()pd.read_feather()데이터를 R- 호환 페더 이진 형식으로 초고속으로 저장합니다 (제 손에는 pandas.to_pickle()숫자 데이터 보다 약간 빠르며 문자열 데이터에서는 훨씬 빠릅니다).

stackoverflow에 대한이 답변 에 관심 있을 수도 있습니다 .


to_feather문자열 데이터에서 잘 작동 하는지 알고 있습니까? 나는 벤치 마크 to_pickle하고 to_feature숫자 데이터 프레임과 피클이 약 3 배 빠릅니다.
zyxue

@zyxue 좋은 질문, 나는 솔직히 깃털 물건을 많이 연주하지 않았기 때문에 대답이 없습니다.
Noah

20

피클은 잘 작동합니다!

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
생성 된 파일은 CSV 파일이 아니므 .pkl로 @Andy Haydens 답변에 제안 된 확장명을 사용하는 것이 좋습니다.
a 금

5

페더 형식 파일을 사용할 수 있습니다. 매우 빠릅니다.

df.to_feather('filename.ft')

그런 다음 라이브러리 를 R사용하여 데이터를 직접 사용할 수 feather있습니다.
James Hirschorn

4

Pandas DataFrame에는 DataFrame to_pickle을 저장하는 데 유용한 기능이 있습니다.

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

이미 언급했듯이 데이터 프레임을 저장하기위한 다양한 옵션 및 파일 형식 ( HDF5 , JSON , CSV , parquet , SQL )이 있습니다. 그러나 다음과 같은 pickle이유로 일급 시민이 아닙니다 (설정에 따라 다름).

  1. pickle잠재적 인 보안 위험입니다. pickle에 대한 Python 문서를 작성하십시오 .

경고pickle 모듈은 잘못된 또는 악의적으로 제작 된 데이터에 대한 보안 상 안전하지 않을 수 있습니다. 신뢰할 수 없거나 인증되지 않은 소스에서받은 데이터를 피클 링하지 마십시오.

  1. pickle느리다. 여기여기에서 벤치 마크를 찾으 십시오 .

설정 / 사용법에 따라 두 제한 사항이 모두 적용되지는 않지만 pickle팬더 데이터 프레임의 기본 지속성으로 권장하지 않습니다 .


1

Numpy 파일 형식은 수치 데이터에 매우 빠릅니다.

numpy 파일은 빠르고 작업하기 쉽기 때문에 numpy 파일을 사용하는 것을 선호합니다. 다음은 1 열 1 백만 포인트의 데이터 프레임을 저장하고로드하기위한 간단한 벤치 마크입니다.

import numpy as np
import pandas as pd

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

ipython의 %%timeit마술 함수 사용

%%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

나쁘지 않다!

단점

python 2를 사용하여 numpy 파일을 저장 한 다음 python 3을 사용하여 열거 나 그 반대의 경우 문제가 있습니다.


6
이 솔루션은 모든 열 이름을 삭제하고 모든 정수 데이터를 float로 변경합니다. (
Joseph Garvin

0

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

피클 프로토콜 형식 :

프로토콜 버전 0은 원래 "사람이 읽을 수있는"프로토콜이며 이전 버전의 Python과 호환됩니다.

프로토콜 버전 1은 이전 이진 형식이며 이전 버전의 Python 과도 호환됩니다.

프로토콜 버전 2는 Python 2.3에서 도입되었습니다. 새로운 스타일의 클래스를 훨씬 더 효율적으로 산 세척합니다. 프로토콜 2의 개선 사항에 대한 정보는 PEP 307을 참조하십시오.

프로토콜 버전 3은 Python 3.0에 추가되었습니다. 바이트 객체를 명시 적으로 지원하며 Python 2.x에서 피클 링 할 수 없습니다. 이것은 기본 프로토콜이며 다른 Python 3 버전과의 호환성이 필요한 경우 권장되는 프로토콜입니다.

프로토콜 버전 4는 Python 3.4에서 추가되었습니다. 매우 큰 객체, 더 많은 종류의 객체 및 일부 데이터 형식 최적화를 지원합니다. 프로토콜 4의 개선 사항에 대한 정보는 PEP 3154를 참조하십시오.


0

버전 간 pyarrow 호환성

전반적인 이동은 pyarrow / feather (pandas / msgpack의 지원 중단 경고)입니다. 그러나 사양에 일시적인 pyarrow가있는 문제가 있습니다. pyarrow 0.15.1로 직렬화 된 데이터는 0.16.0 ARROW-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주피터 변수)

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

깃털과 쪽모이 세공이 내 데이터 프레임에서 작동하지 않습니다. 나는 pyarrow를 계속 사용할 것입니다. 그러나 나는 피클 (압축 없음)을 보충 할 것입니다. 저장소 파이로 및 피클 직렬화 된 양식을 캐시하기 위해 쓸 때. pyarrow deserialisation이 실패하면 캐시 폴백에서 피클로 읽을 때.


이 질문에 대답하지 않습니다
Jason S

0

형식은 사용 사례에 따라 다릅니다.

  • 노트북 세션 사이에 저장 DataFrame - 깃털 , 당신이하는 데 사용하는 경우 피클 -도 OK입니다.
  • 가능한 가장 작은 파일 크기로 DataFrame 저장- 쪽모이 세공 또는 pickle.gz (데이터에 더 적합한 것을 확인)
  • 매우 큰 DataFrame을 (행 10 개 + 수백만) 저장 - HDF를
  • csv , csv.gz 등의 다른 형식을 지원하지 않는 다른 플랫폼 (Python 아님)의 데이터를 읽을 수 있어야 합니다. 마루 가 지원 되는지 확인하십시오.
  • 눈으로보고 / Excel / Google 스프레드 시트 / Git diff 사용 -CSV
  • 거의 모든 RAM을 소요 DataFrame 저장 - CSV

팬더 파일 형식의 비교는 이 비디오에 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.