การเปิดไฟล์ 20GB สำหรับการวิเคราะห์ด้วยแพนด้า


33

ฉันกำลังพยายามเปิดไฟล์ที่มี pandas และ python เพื่อการเรียนรู้ของเครื่องมันจะเหมาะสำหรับฉันที่จะมีพวกเขาทั้งหมดใน DataFrame ตอนนี้ไฟล์มีขนาดใหญ่ 18GB และ RAM ของฉันคือ 32 GB แต่ฉันยังคงได้รับข้อผิดพลาดของหน่วยความจำ

จากประสบการณ์ของคุณเป็นไปได้ไหม ถ้าคุณไม่ทราบวิธีที่ดีกว่าที่จะไปรอบ ๆ นี้? (ตารางรังผึ้งเพิ่มขนาด RAM ของฉันเป็น 64 สร้างฐานข้อมูลและเข้าถึงจากงูหลาม)


ฉันมีปัญหาเดียวกันฉันขอแนะนำให้คุณเพิ่ม swap, เพจจิ้ง, ขนาดของฮาร์ดไดรฟ์ของคุณ
สื่อ

กฎของหัวแม่มือเมื่อโหลดข้อมูลpandasคือคุณต้องมี RAM เพิ่มขึ้น 5-10 เท่า ฉันแนะนำให้ทำการinplaceดำเนินการอย่างชัดเจนเรียกgarbage.collectorการจัดสรรวัตถุ
Kiritee Gak

4
ทำให้คำถามนี้ดีขึ้นโดยการระบุเป้าหมายสุดท้ายของคุณ คุณกำลังทำการวิเคราะห์ข้อมูลเชิงสำรวจทำความสะอาดข้อมูลฝึกอบรมแบบจำลองหรือไม่? ข้อมูลประเภทใด
Pete

1
คุณเคยคิดที่จะใช้daskไหม?
rpanai

คำตอบ:


32

หากเป็นไฟล์ csv และคุณไม่จำเป็นต้องเข้าถึงข้อมูลทั้งหมดในครั้งเดียวขณะฝึกอัลกอริทึมของคุณคุณสามารถอ่านได้ในหน่วยย่อย pandas.read_csvวิธีช่วยให้คุณสามารถอ่านไฟล์ใน chunks เช่นนี้:

import pandas as pd
for chunk in pd.read_csv(<filepath>, chunksize=<your_chunksize_here>)
    do_processing()
    train_algorithm()

นี่คือเอกสารของวิธีการ


สิ่งนี้นำไปใช้กับไฟล์ zip เช่นกัน?
James Wierzba

มันควรจะทำงานถ้าไฟล์ซิปเป็นไฟล์ csv ด้วยคุณจะต้องผ่านประเภทการบีบอัดเพื่อเป็นข้อโต้แย้งกับวิธีนี้
Olel Daniel

22

มีความเป็นไปได้สองอย่าง: คุณต้องการมีข้อมูลทั้งหมดในหน่วยความจำสำหรับการประมวลผล (เช่นอัลกอริทึมการเรียนรู้ของเครื่องจะต้องการกินมันทั้งหมดในครั้งเดียว) หรือคุณสามารถทำได้โดยไม่ต้องใช้มัน คอลัมน์พร้อมกัน)

ในกรณีแรกคุณจะต้องแก้ปัญหาหน่วยความจำแก้ปัญหาหน่วยความจำเพิ่มขนาดหน่วยความจำของคุณเช่าเครื่องคลาวด์หน่วยความจำสูงใช้การดำเนินการแบบ inplace ให้ข้อมูลเกี่ยวกับประเภทของข้อมูลที่คุณกำลังอ่านตรวจสอบให้แน่ใจว่าได้ลบตัวแปรที่ไม่ได้ใช้ทั้งหมดและรวบรวมขยะ ฯลฯ

เป็นไปได้มากว่า RAM ขนาด 32GB จะไม่เพียงพอที่ Pandas จะจัดการกับข้อมูลของคุณ โปรดทราบว่าจำนวนเต็ม "1" เป็นเพียงหนึ่งไบต์เมื่อเก็บเป็นข้อความ แต่ 8 ไบต์เมื่อแสดงเป็นint64(ซึ่งเป็นค่าเริ่มต้นเมื่อ Pandas อ่านจากข้อความ) คุณสามารถทำตัวอย่างเดียวกันกับตัวเลขจุดลอยตัว "1.0" ซึ่งขยายจากสตริง 3 ไบต์เป็น 8 ไบต์float64ตามค่าเริ่มต้น คุณอาจชนะพื้นที่บางส่วนได้โดยแจ้งให้ Pandas ทราบอย่างแม่นยำว่าจะใช้ประเภทใดในแต่ละคอลัมน์และบังคับให้มีการแทนค่าที่เป็นไปได้น้อยที่สุด แต่เราไม่ได้เริ่มพูดถึงโครงสร้างข้อมูลของ Python ที่นี่ซึ่งอาจเพิ่มตัวชี้พิเศษ และตัวชี้คือ 8 ไบต์แต่ละตัวบนเครื่อง 64- บิต

ในการสรุป: ไม่ RAM 32GB อาจไม่เพียงพอที่ Pandas จะจัดการกับไฟล์ 20GB

ในกรณีที่สอง (ซึ่งเป็นจริงมากขึ้นและอาจจะนำไปใช้กับคุณ) คุณจะต้องแก้ปัญหาการจัดการข้อมูล ที่จริงแล้วการโหลดข้อมูลทั้งหมดเมื่อคุณต้องการเพียงบางส่วนในการประมวลผลอาจเป็นสัญญาณของการจัดการข้อมูลที่ไม่ดี มีหลายตัวเลือกที่นี่:

  1. ใช้ฐานข้อมูล SQL หากคุณสามารถทำได้มันเป็นทางเลือกแรกและเป็นทางออกที่สะดวกสบายพอสมควร 20GB ดูเหมือนว่าขนาดฐานข้อมูล SQL ส่วนใหญ่จะจัดการได้ดีโดยไม่จำเป็นต้องเผยแพร่แม้ในแล็ปท็อป (ระดับบน) คุณจะสามารถคอลัมน์ดัชนีทำแรพื้นฐานผ่าน SQL และได้รับ subsamples pd.read_sqlจำเป็นลงในนุ่นสำหรับการประมวลผลที่ซับซ้อนมากขึ้นโดยใช้ที่เรียบง่าย การย้ายข้อมูลไปยังฐานข้อมูลนอกจากนี้ยังจะช่วยให้คุณมีโอกาสที่จะคิดเกี่ยวกับที่เกิดขึ้นจริงชนิดข้อมูลและขนาดของคอลัมน์ของคุณ

  2. หากข้อมูลของคุณส่วนใหญ่เป็นตัวเลข (เช่นอาร์เรย์หรือเทนเซอร์) คุณอาจลองถือในรูปแบบ HDF5 (ดูPyTables ) ซึ่งช่วยให้คุณสามารถอ่านเฉพาะส่วนที่จำเป็นของอาร์เรย์ขนาดใหญ่จากดิสก์ Basic numpy.save และ numpy.loadบรรลุผลเช่นเดียวกันผ่านการแม็ปหน่วยความจำในอาร์เรย์บนดิสก์เช่นกัน สำหรับ GIS และข้อมูลแรสเตอร์ที่เกี่ยวข้องมีฐานข้อมูลเฉพาะ ซึ่งอาจไม่เชื่อมต่อกับหมีแพนด้าเหมือนกับ SQL โดยตรง แต่ควรอนุญาตให้คุณแบ่งส่วนและสอบถามอย่างสะดวกสบาย

  3. Pandas ไม่สนับสนุนการแมปหน่วยความจำ "บางส่วน" ของ HDF5 หรืออาร์เรย์ numpy เท่าที่ฉันรู้ หากคุณยังต้องการวิธีแก้ปัญหา "pure-pandas" คุณสามารถลองใช้วิธี "sharding": จัดเก็บคอลัมน์ของตารางขนาดใหญ่ของคุณแยกจากกัน (เช่นในไฟล์แยกหรือในตาราง "แยก" ของ HDF5 เดียว ไฟล์) และโหลดเฉพาะสิ่งที่จำเป็นตามต้องการหรือจัดเก็บชิ้นส่วนของแถวแยกกัน อย่างไรก็ตามคุณจะต้องใช้ตรรกะในการโหลดชิ้นส่วนที่จำเป็นดังนั้นการสร้างจักรยานใหม่ที่มีอยู่แล้วในฐานข้อมูล SQL ส่วนใหญ่ดังนั้นตัวเลือกที่ 1 อาจจะง่ายกว่าที่นี่ อย่างไรก็ตามหากข้อมูลของคุณอยู่ในรูปแบบ CSV คุณสามารถประมวลผลเป็นชิ้น ๆ โดยระบุchunksizeพารามิเตอร์เป็นpd.read_csvพารามิเตอร์


5
สิ่งที่ควรกล่าวถึงใน "กรณีแรก" คือถ้า OP มีรายการจำนวนมากที่มีค่าเดียวกันในข้อมูล (เช่นศูนย์) ข้อมูลจะถูกพูดแบบเบาบางและเมทริกซ์กระจัดกระจายสามารถใช้แทน pafas dataframe - sparse data ต้องการหน่วยความจำน้อยกว่ามาก
Ricardo Cruz

9

ฉันเพิ่งมีปัญหานี้ไม่กี่วันที่ผ่านมา! ไม่แน่ใจว่าสิ่งนี้จะช่วยได้ในกรณีเฉพาะของคุณหรือไม่เนื่องจากคุณไม่ได้ให้รายละเอียดมากมาย แต่สถานการณ์ของฉันคือการทำงานออฟไลน์ในชุดข้อมูล 'ใหญ่' ข้อมูลได้รับเป็นไฟล์ CSV 20GB gzipped จากเครื่องวัดพลังงานข้อมูลอนุกรมเวลาในช่วงเวลาหลายวินาที

ไฟล์ IO:

data_root = r"/media/usr/USB STICK"
fname = r"meters001-050-timestamps.csv.gz"
this_file = os.path.join(data_root,fname)
assert os.path.exists(this_file), this_file
this_file

สร้าง chunk iterator โดยตรงเหนือไฟล์ gzip (ห้าม unzip!)

cols_to_keep = [0,1,2,3,7]
column_names = ['METERID','TSTAMP','ENERGY','POWER_ALL','ENERGY_OUT',]
parse_dates = ['TSTAMP']
dtype={'METERID': np.int32, 
       'ENERGY': np.int32,
       'POWER_ALL': np.int32,
       'ENERGY_OUT': np.int32,
      }
df_iterator = pd.read_csv(this_file, 
                        skiprows=0, 
                        compression='gzip',
                        chunksize=1000000, 
                        usecols=cols_to_keep,
                        delimiter=";",
                        header=None,
                        names = column_names,
                      dtype=dtype,
                     parse_dates=parse_dates,
                     index_col=1,
                     )

วนซ้ำทุกชิ้น

new_df = pd.DataFrame()
count = 0
for df in df_iterator:
    chunk_df_15min = df.resample('15T').first()
    #chunk_df_30min = df.resample('30T').first()
    #chunk_df_hourly = df.resample('H').first()
    this_df = chunk_df_15min
    this_df = this_df.pipe(lambda x: x[x.METERID == 1])
    #print("chunk",i)
    new_df = pd.concat([new_df,chunk_df_15min])
    print("chunk",count, len(chunk_df_15min), 'rows added')
    #print("chunk",i, len(temp_df),'rows added')
    #break
    count += 1

ในวงอันธพาลฉันกำลังทำการกรองและสุ่มตัวอย่างตรงเวลา การทำเช่นนี้ฉันลดขนาดจาก 20GB เหลือเพียงไม่กี่ร้อย MB HDF5 สำหรับการสำรวจข้อมูลออฟไลน์เพิ่มเติม


5

จากประสบการณ์ของฉันการเริ่มต้นread_csv()ด้วยพารามิเตอร์low_memory=Falseมีแนวโน้มที่จะช่วยเหลือเมื่ออ่านไฟล์ขนาดใหญ่ ฉันไม่คิดว่าคุณได้พูดถึงประเภทของไฟล์ที่คุณกำลังอ่านอยู่ดังนั้นฉันไม่แน่ใจว่าจะใช้งานได้อย่างไรกับสถานการณ์ของคุณ


1

หากไฟล์ของคุณเป็นไฟล์ CSV คุณสามารถทำได้ง่ายๆด้วย Chunk by Chunk คุณสามารถทำได้ง่ายๆ

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.