ตอนนี้ฉันกำลังนำเข้าไฟล์ข้อมูลขนาดใหญ่พอสมควร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 ( pytables ) ซึ่งมีเวลาเข้าถึงที่รวดเร็วมากสำหรับชุดข้อมูลขนาดใหญ่:
store = HDFStore('store.h5')
store['df'] = df # save it
store['df'] # load it
กลยุทธ์ขั้นสูงอื่น ๆ ที่จะกล่าวถึงในตำรา
ตั้งแต่ 0.13 นอกจากนี้ยังมีmsgpackซึ่งอาจจะดีกว่าสำหรับการทำงานร่วมกันเป็นทางเลือกที่เร็วกว่าสำหรับ JSON หรือถ้าคุณมีข้อมูลของออบเจ็กต์หลาม / ข้อความหนัก ๆ (ดูคำถามนี้ )
แม้ว่าจะมีคำตอบบางอย่างแล้วผมพบว่าการเปรียบเทียบที่ดีในการที่พวกเขาพยายามหลายวิธีที่จะเป็นอันดับนุ่น DataFrames: มีประสิทธิภาพร้านนุ่น DataFrames
พวกเขาเปรียบเทียบ:
ในการทดสอบพวกเขาจะทำการเรียงลำดับ DataFrame 1,000,000 แถวด้วยการทดสอบสองคอลัมน์แยกกัน: หนึ่งรายการกับข้อมูลข้อความและอีกคอลัมน์หนึ่งพร้อมตัวเลข ข้อจำกัดความรับผิดชอบของพวกเขาพูดว่า:
คุณไม่ควรเชื่อมั่นว่าสิ่งต่อไปนี้เป็นการสรุปข้อมูลของคุณ คุณควรดูข้อมูลของคุณเองและทำการทดสอบด้วยตนเอง
รหัสที่มาสำหรับการทดสอบซึ่งพวกเขาเรียกใช้ได้ออนไลน์ เนื่องจากรหัสนี้ไม่ทำงานโดยตรงฉันได้ทำการเปลี่ยนแปลงเล็กน้อยซึ่งคุณสามารถรับได้ที่นี่: serialize.py ฉันได้รับผลลัพธ์ต่อไปนี้:
พวกเขายังกล่าวด้วยว่าด้วยการแปลงข้อมูลข้อความเป็นข้อมูลที่เป็นหมวดหมู่การทำให้เป็นอนุกรมนั้นเร็วกว่ามาก ในการทดสอบของพวกเขาประมาณ 10 ครั้งเร็ว (ดูรหัสทดสอบ)
แก้ไข : เวลาในการดองมากกว่า CSV สามารถอธิบายได้ด้วยรูปแบบข้อมูลที่ใช้ โดยค่าเริ่มต้นpickle
ใช้การแสดง ASCII ที่พิมพ์ได้ซึ่งสร้างชุดข้อมูลที่ใหญ่กว่า ดังที่สามารถเห็นได้จากกราฟอย่างไรก็ตาม pickle ที่ใช้รูปแบบข้อมูลไบนารีใหม่ (รุ่น 2 pickle-p2
) มีเวลาในการโหลดน้อยกว่ามาก
ข้อมูลอ้างอิงอื่น ๆ :
numpy.fromfile
นั้นเร็วที่สุด.to_pickle()
(ซึ่งใช้ที่เก็บข้อมูลไบนารี) เทียบกับ.to_hdf()
(โดยไม่บีบอัด) เป้าหมายคือความเร็วขนาดไฟล์สำหรับ HDF คือ 11x Pickle และเวลาในการโหลด คือ 5x Pickle ข้อมูลของฉันคือ ~ 5k ไฟล์ของ ~ 7k แถว x 6 คอลัมน์แต่ละส่วนใหญ่เป็นตัวเลข
ถ้าฉันเข้าใจถูกต้องคุณกำลังใช้อยู่แล้วpandas.read_csv()
แต่ต้องการเร่งกระบวนการพัฒนาเพื่อให้คุณไม่ต้องโหลดไฟล์ทุกครั้งที่คุณแก้ไขสคริปต์ใช่ไหม? ฉันมีคำแนะนำเล็กน้อย:
คุณสามารถโหลดไฟล์ CSV เพียงบางส่วนที่ใช้pandas.read_csv(..., nrows=1000)
เพื่อโหลดบิตบนสุดของตารางในขณะที่คุณกำลังพัฒนา
ใช้ipythonสำหรับเซสชันแบบโต้ตอบเช่นที่คุณเก็บตารางหมีแพนด้าไว้ในหน่วยความจำในขณะที่คุณแก้ไขและโหลดสคริปต์ของคุณใหม่
แปลง csv เป็นตาราง HDF5
การปรับปรุงการใช้งานDataFrame.to_feather()
และpd.read_feather()
การเก็บข้อมูลในการวิจัยได้ขนรูปแบบไบนารีที่เป็นซุปเปอร์รวดเร็ว (อยู่ในมือของฉันเล็กน้อยเร็วกว่าpandas.to_pickle()
บนข้อมูลที่เป็นตัวเลขและเร็วขึ้นมากกับข้อมูลสตริง)
คุณอาจสนใจคำตอบนี้ใน stackoverflow
to_feather
จะทำงานได้ดีกับข้อมูลสตริง? ฉันวัดประสิทธิผลto_pickle
และto_feature
ใน dataframe ตัวเลขของฉันและดองเป็นเรื่องเกี่ยวกับ 3x เร็วขึ้น
ผักดองทำงานได้ดี!
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 answer
คุณสามารถใช้ไฟล์รูปแบบขนนก มันเร็วมาก
df.to_feather('filename.ft')
R
ใช้feather
ห้องสมุด
Pandas 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 , parquet , SQL ) เพื่อจัดเก็บกรอบข้อมูล อย่างไรก็ตามpickle
ไม่ใช่พลเมืองชั้นหนึ่ง (ขึ้นอยู่กับการตั้งค่าของคุณ) เนื่องจาก:
pickle
ความเสี่ยงด้านความปลอดภัยที่อาจเกิดขึ้น สร้างเอกสาร Python สำหรับการดอง :คำเตือน
pickle
โมดูลจะไม่ปลอดภัยกับข้อมูลที่ผิดพลาดหรือสร้างมีเจตนาร้าย อย่าถอนการรวบรวมข้อมูลที่ได้รับจากแหล่งที่ไม่น่าเชื่อถือหรือไม่ได้รับการรับรองความถูกต้อง
ขึ้นอยู่กับการตั้งค่า / การใช้งานของคุณทั้งสองข้อ จำกัด ใช้ไม่ได้ แต่ฉันจะไม่แนะนำpickle
เป็นค่าเริ่มต้นสำหรับการคงอยู่ของเฟรมข้อมูลแพนด้า
ฉันชอบที่จะใช้ไฟล์ numpy เพราะมันรวดเร็วและใช้งานง่าย นี่คือมาตรฐานง่ายๆสำหรับการบันทึกและโหลดดาต้าเฟรมที่มี 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
เพื่อโหลดข้อมูลกลับสู่ dataframe
%%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
รูปแบบโปรโตคอล pickle:
โพรโทคอลรุ่น 0 เป็นโปรโตคอลดั้งเดิมที่“ มนุษย์อ่านได้” และเข้ากันได้กับ Python รุ่นก่อนหน้า
Protocol version 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
การเคลื่อนไหวโดยรวมนั้นเป็นการทำที่แคบ / ขนนก แต่ฉันมีความท้าทายกับ pyarrow กับชั่วคราวในสเปคข้อมูลต่อเนื่องกับ pyarrow 0.15.1 ไม่สามารถ deserialized กับ 0.16.0 ลูกศร-7961 ฉันใช้การทำให้เป็นอนุกรมเพื่อใช้ redis ดังนั้นต้องใช้การเข้ารหัสไบนารี
ฉันได้ลองตัวเลือกต่าง ๆ อีกครั้ง (โดยใช้สมุดบันทึก 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")
ด้วยผลลัพธ์ต่อไปนี้สำหรับ data frame ของฉัน (ใน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>
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
ขนนกและปาร์เก้ไม่ทำงานกับกรอบข้อมูลของฉัน ฉันจะใช้ pyarrow ต่อไป อย่างไรก็ตามฉันจะเสริมด้วยดอง (ไม่มีการบีบอัด) เมื่อเขียนไปยังแคชร้านค้ารูปแบบ pyarrow และดองต่อเนื่อง เมื่ออ่านจากแคชทางเลือกในการดองถ้า pyram deserialisation ล้มเหลว
รูปแบบขึ้นอยู่กับการใช้งานของคุณ
การเปรียบเทียบรูปแบบไฟล์แพนด้าอยู่ในวิดีโอนี้