Ngay bây giờ tôi đang nhập CSV
một tệp dữ liệu khá lớn mỗi khi tôi chạy tập lệnh. Có một giải pháp tốt để giữ cho khung dữ liệu đó liên tục có sẵn ở giữa các lần chạy để tôi không phải dành toàn bộ thời gian chờ đợi tập lệnh chạy không?
Ngay bây giờ tôi đang nhập CSV
một tệp dữ liệu khá lớn mỗi khi tôi chạy tập lệnh. Có một giải pháp tốt để giữ cho khung dữ liệu đó liên tục có sẵn ở giữa các lần chạy để tôi không phải dành toàn bộ thời gian chờ đợi tập lệnh chạy không?
Câu trả lời:
Cách dễ nhất là ngâm nó bằng cách sử dụng to_pickle
:
df.to_pickle(file_name) # where to save it, usually as a .pkl
Sau đó, bạn có thể tải lại bằng cách sử dụng:
df = pd.read_pickle(file_name)
Lưu ý: trước 0.11.1 save
và load
là cách duy nhất để thực hiện việc này (hiện tại chúng không được hỗ trợ to_pickle
và read_pickle
tương ứng).
Một lựa chọn phổ biến khác là sử dụng HDF5 ( pytables ) cung cấp thời gian truy cập rất nhanh cho các bộ dữ liệu lớn:
store = HDFStore('store.h5')
store['df'] = df # save it
store['df'] # load it
Các chiến lược nâng cao hơn được thảo luận trong sách dạy nấu ăn .
Vì 0.13 cũng có gói tin có thể tốt hơn cho khả năng tương tác, như là một thay thế nhanh hơn cho JSON hoặc nếu bạn có dữ liệu nặng về đối tượng / văn bản (xem câu hỏi này ).
Mặc dù đã có một số câu trả lời tôi đã tìm thấy một so sánh hay, trong đó họ đã thử một số cách để tuần tự hóa Pandas DataFrames: Lưu trữ hiệu quả Pandas DataFrames .
Họ so sánh:
Trong thử nghiệm của họ, họ tuần tự hóa một DataFrame gồm 1.000.000 hàng với hai cột được kiểm tra riêng: một cột có dữ liệu văn bản, cột kia có số. Tuyên bố từ chối trách nhiệm của họ nói:
Bạn không nên tin tưởng rằng những gì tiếp theo sẽ khái quát hóa dữ liệu của bạn. Bạn nên xem dữ liệu của riêng bạn và tự chạy điểm chuẩn
Mã nguồn cho bài kiểm tra mà họ đề cập có sẵn trực tuyến . Vì mã này không hoạt động trực tiếp nên tôi đã thực hiện một số thay đổi nhỏ, bạn có thể nhận được ở đây: serialize.py Tôi nhận được các kết quả sau:
Họ cũng đề cập rằng với việc chuyển đổi dữ liệu văn bản thành dữ liệu phân loại, việc tuần tự hóa nhanh hơn nhiều. Trong thử nghiệm của họ nhanh gấp khoảng 10 lần (cũng xem mã kiểm tra).
Chỉnh sửa : Thời gian cao hơn cho dưa chua so với CSV có thể được giải thích bằng định dạng dữ liệu được sử dụng. Theo mặc định, pickle
sử dụng biểu diễn ASCII có thể in được, tạo ra các tập dữ liệu lớn hơn. Tuy nhiên, có thể thấy từ biểu đồ, dưa chua sử dụng định dạng dữ liệu nhị phân mới hơn (phiên bản 2, pickle-p2
) có thời gian tải thấp hơn nhiều.
Một số tài liệu tham khảo khác:
numpy.fromfile
là nhanh nhất..to_pickle()
(sử dụng lưu trữ nhị phân) so với .to_hdf()
(không nén). Mục tiêu là tốc độ, kích thước tệp cho HDF là 11x Pickle và thời gian tải là 5x Pickle. Dữ liệu của tôi là ~ 5k tệp với ~ 7k hàng x 6 cols mỗi tệp, chủ yếu là số.
Nếu tôi hiểu chính xác, bạn đã sử dụng pandas.read_csv()
nhưng muốn tăng tốc quá trình phát triển để bạn không phải tải tệp mỗi khi bạn chỉnh sửa tập lệnh của mình, điều đó có đúng không? Tôi có một vài đề xuất:
bạn chỉ có thể tải một phần của tệp CSV bằng cách pandas.read_csv(..., nrows=1000)
chỉ tải bit trên cùng của bảng trong khi bạn đang thực hiện phát triển
sử dụng ipython cho một phiên tương tác, sao cho bạn giữ bảng gấu trúc trong bộ nhớ khi bạn chỉnh sửa và tải lại tập lệnh của mình.
chuyển đổi csv thành bảng HDF5
cập nhật sử dụng DataFrame.to_feather()
và pd.read_feather()
lưu trữ dữ liệu ở định dạng nhị phân lông tương thích R siêu nhanh (trong tay tôi, nhanh hơn một chút so với pandas.to_pickle()
dữ liệu số và nhanh hơn nhiều trên dữ liệu chuỗi).
Bạn cũng có thể quan tâm đến câu trả lời này trên stackoverflow.
to_feather
sẽ hoạt động tốt trên dữ liệu chuỗi? Tôi đã điểm chuẩn to_pickle
và to_feature
trên khung dữ liệu số và dưa chua của tôi nhanh hơn khoảng 3 lần.
Pickle hoạt động tốt!
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
như được đề xuất trong câu trả lời @Andy Haydens.
Bạn có thể sử dụng tập tin định dạng lông. Nó cực kỳ nhanh.
df.to_feather('filename.ft')
R
cách sử dụng feather
thư viện.
Pandas DataFrames có to_pickle
chức năng hữu ích để lưu 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
Như đã đề cập, có các tùy chọn và định dạng tệp khác nhau ( HDF5 , JSON , CSV , parquet , SQL ) để lưu trữ khung dữ liệu. Tuy nhiên, pickle
không phải là công dân hạng nhất (tùy thuộc vào thiết lập của bạn), bởi vì:
pickle
là một rủi ro bảo mật tiềm năng. Hình thành tài liệu Python cho dưa chua :Cảnh báo Các
pickle
mô-đun không phải là an toàn đối với dữ liệu có sai sót hoặc cố xây dựng. Không bao giờ tháo dữ liệu nhận được từ một nguồn không đáng tin cậy hoặc không được xác thực.
Tùy thuộc vào thiết lập / sử dụng của bạn, cả hai giới hạn đều không áp dụng, nhưng tôi không khuyến nghị sử dụng pickle
như là sự tồn tại mặc định cho các khung dữ liệu của gấu trúc.
Tôi thích sử dụng các tệp numpy vì chúng nhanh và dễ làm việc. Đây là một điểm chuẩn đơn giản để lưu và tải một khung dữ liệu với 1 cột 1 triệu điểm.
import numpy as np
import pandas as pd
num_dict = {'voltage': np.random.rand(1000000)}
num_df = pd.DataFrame(num_dict)
sử dụng %%timeit
chức năng ma thuật của ipython
%%timeit
with open('num.npy', 'wb') as np_file:
np.save(np_file, num_df)
đầu ra là
100 loops, best of 3: 5.97 ms per loop
để tải dữ liệu trở lại vào khung dữ liệu
%%timeit
with open('num.npy', 'rb') as np_file:
data = np.load(np_file)
data_df = pd.DataFrame(data)
đầu ra là
100 loops, best of 3: 5.12 ms per loop
KHÔNG TỆ!
Có vấn đề nếu bạn lưu tệp numpy bằng python 2 và sau đó thử mở bằng python 3 (hoặc ngược lại).
https://docs.python.org/3/l Library / topperle.html
Các định dạng giao thức dưa chua:
Giao thức phiên bản 0 là giao thức gốc có thể đọc được của con người và có khả năng tương thích ngược với các phiên bản trước của Python.
Giao thức phiên bản 1 là định dạng nhị phân cũ cũng tương thích với các phiên bản trước của Python.
Giao thức phiên bản 2 đã được giới thiệu trong Python 2.3. Nó cung cấp hiệu quả hơn nhiều cho các lớp học kiểu mới. Tham khảo PEP 307 để biết thông tin về các cải tiến do giao thức 2 mang lại.
Giao thức phiên bản 3 đã được thêm vào Python 3.0. Nó có hỗ trợ rõ ràng cho các đối tượng byte và không thể được giải nén bởi Python 2.x. Đây là giao thức mặc định và giao thức được đề xuất khi cần tương thích với các phiên bản Python 3 khác.
Giao thức phiên bản 4 đã được thêm vào Python 3.4. Nó bổ sung hỗ trợ cho các đối tượng rất lớn, chọn nhiều loại đối tượng hơn và một số tối ưu hóa định dạng dữ liệu. Tham khảo PEP 3154 để biết thông tin về các cải tiến do giao thức 4 mang lại.
Di chuyển tổng thể đã được chuyển đến pyarrow / lông (cảnh báo khấu hao từ gấu trúc / Trình thông báo). Tuy nhiên, tôi có một thách thức với pyarrow với đặc điểm tạm thời Dữ liệu được tuần tự hóa với pyarrow 0.15.1 không thể được giải tuần tự hóa với 0.16.0 MROWI -7961 . Tôi đang sử dụng tuần tự hóa để sử dụng redis vì vậy phải sử dụng mã hóa nhị phân.
Tôi đã kiểm tra lại các tùy chọn khác nhau (sử dụng sổ ghi chép 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")
Với các kết quả sau cho khung dữ liệu của tôi (trong out
biến 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>
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
lông và sàn gỗ không hoạt động cho khung dữ liệu của tôi. Tôi sẽ tiếp tục sử dụng pyarrow. Tuy nhiên tôi sẽ bổ sung với dưa chua (không nén). Khi ghi vào bộ nhớ cache lưu trữ các biểu mẫu pyarrow và dưa chua. Khi đọc từ dự phòng bộ đệm đến dưa chua nếu khử lưu huỳnh pyarrow không thành công.
Định dạng tùy thuộc vào trường hợp sử dụng của bạn
So sánh các định dạng tệp gấu trúc có trong video này .