DataFrame ขนาดใหญ่และถาวรในแพนด้า


93

ฉันกำลังสำรวจการเปลี่ยนไปใช้ python และ pandas ในฐานะผู้ใช้ SAS เป็นเวลานาน

อย่างไรก็ตามเมื่อทำการทดสอบในวันนี้ฉันรู้สึกประหลาดใจที่ python มีหน่วยความจำpandas.read_csv()ไม่เพียงพอเมื่อพยายามใช้ไฟล์ csv ขนาด 128mb มีข้อมูลตัวเลขประมาณ 200,000 แถวและ 200 คอลัมน์

ด้วย SAS ฉันสามารถนำเข้าไฟล์ csv ไปยังชุดข้อมูล SAS และมีขนาดใหญ่พอ ๆ กับฮาร์ดไดรฟ์ของฉัน

มีบางอย่างที่คล้ายคลึงกันpandasหรือไม่?

ฉันทำงานกับไฟล์ขนาดใหญ่เป็นประจำและไม่มีสิทธิ์เข้าถึงเครือข่ายคอมพิวเตอร์แบบกระจาย


ฉันไม่คุ้นเคยกับแพนด้า แต่คุณอาจต้องการดูการทำซ้ำในไฟล์ pandas.pydata.org/pandas-docs/stable/…
monkut

คำตอบ:


80

โดยหลักการแล้วหน่วยความจำไม่ควรจะหมด แต่ในขณะนี้มีปัญหาหน่วยความจำread_csvในไฟล์ขนาดใหญ่ที่เกิดจากปัญหาภายในของ Python ที่ซับซ้อน (สิ่งนี้คลุมเครือ แต่เป็นที่ทราบกันมานานแล้ว: http://github.com/pydata / แพนด้า / ประเด็น / 407 )

ในขณะนี้ยังไม่มีวิธีแก้ปัญหาที่สมบูรณ์แบบ (นี่เป็นวิธีที่น่าเบื่อ: คุณสามารถถอดเสียงไฟล์ทีละแถวเป็นอาร์เรย์ NumPy ที่จัดสรรไว้ล่วงหน้าหรือไฟล์ที่แมปหน่วยความจำ - np.mmap) แต่เป็นสิ่งที่ฉันจะใช้งานได้ ในอนาคตอันใกล้นี้ อีกวิธีหนึ่งคือการอ่านไฟล์เป็นชิ้นเล็ก ๆ (ใช้iterator=True, chunksize=1000) จากนั้นเชื่อมต่อเข้าด้วยpd.concatกัน ปัญหาจะเกิดขึ้นเมื่อคุณดึงไฟล์ข้อความทั้งหมดไปไว้ในหน่วยความจำในหนึ่งเดียว


1
สมมติว่าฉันสามารถอ่านไฟล์และรวมไฟล์ทั้งหมดเข้าด้วยกันเป็น DataFrame เดียว DataFrame ต้องอยู่ในหน่วยความจำหรือไม่? ด้วย SAS ฉันสามารถทำงานกับชุดข้อมูลได้ทุกขนาดตราบเท่าที่ฉันมีพื้นที่ฮาร์ดไดรฟ์ เหมือนกันกับ DataFrames หรือไม่? ฉันรู้สึกว่าพวกเขาถูก จำกัด โดย RAM และไม่ใช่พื้นที่ฮาร์ดไดรฟ์ ขออภัยสำหรับคำถาม noob และขอบคุณสำหรับความช่วยเหลือ ฉันเพลิดเพลินกับหนังสือของคุณ
Zelazny7

3
ถูกต้องคุณถูก จำกัด โดย RAM SAS รองรับการประมวลผลข้อมูลขนาดใหญ่แบบ "นอกคอร์" ได้ดีกว่ามาก
Wes McKinney

5
@WesMcKinney วิธีแก้ปัญหาเหล่านี้ไม่จำเป็นต้องใช้อีกต่อไปเพราะตัวโหลด csv ใหม่ที่คุณลงจอดใน 0.10 ใช่ไหม?
กาเบรียลแกรนท์

81

Wes ถูกต้อง! ฉันแค่พูดคุยเพื่อให้โค้ดตัวอย่างที่สมบูรณ์มากขึ้น ฉันมีปัญหาเดียวกันกับไฟล์ 129 Mb ซึ่งแก้ไขได้โดย:

import pandas as pd

tp = pd.read_csv('large_dataset.csv', iterator=True, chunksize=1000)  # gives TextFileReader, which is iterable with chunks of 1000 rows.
df = pd.concat(tp, ignore_index=True)  # df is DataFrame. If errors, do `list(tp)` instead of `tp`

6
ฉันคิดว่าคุณสามารถทำได้df = concate(tp, ignore_index=True)?
Andy Hayden

@smci พยายามอย่างรวดเร็วโดยใช้ข้อมูลเดียวกันซ้ำ x4 (550 Mb) หรือ x8 (1.1Gb) ที่น่าสนใจคือมีหรือไม่มี [x สำหรับ x ใน tp] x4 ก็ผ่านไปได้ด้วยดีและ x8 ก็ล้มเหลวใน MemoryError
fickludd

3
AssertionError: first argument must be a list-like of pandas objects, you passed an object of type "TextFileReader"ฉันได้รับข้อผิดพลาดนี้ในขณะที่ใช้มัน มีความคิดว่าเกิดอะไรขึ้นที่นี่?
Prince Kumar

3
ข้อบกพร่องนี้จะได้รับการแก้ไขใน 0.14 (เผยแพร่เร็ว ๆ นี้), github.com/pydata/pandas/pull/6941 ; วิธีแก้ปัญหาสำหรับ <0.14.0 คือสิ่งที่ต้องทำpd.concat(list(tp), ignore_index=True)
เจฟฟ์

1
จะเกิดอะไรขึ้นถ้าค่าเป็นสตริงหรือหมวดหมู่ - ฉันได้รับข้อผิดพลาด: หมวดหมู่ที่เข้ากันไม่ได้ในการเชื่อมต่อแบบแยกประเภท
As3adTintin

41

นี่เป็นเธรดที่เก่ากว่า แต่ฉันแค่ต้องการทิ้งวิธีแก้ปัญหาของฉันที่นี่ ตอนแรกฉันลองใช้chunksizeพารามิเตอร์ (แม้จะมีค่าค่อนข้างน้อยเช่น 10,000) แต่ก็ไม่ได้ช่วยอะไรมาก ยังคงมีปัญหาทางเทคนิคเกี่ยวกับขนาดหน่วยความจำ (CSV ของฉันคือ ~ 7.5 Gb)

ตอนนี้ฉันเพิ่งอ่านไฟล์ CSV ในรูปแบบ for-loop และเพิ่มเข้าไปในฐานข้อมูล SQLite ทีละขั้นตอน:

import pandas as pd
import sqlite3
from pandas.io import sql
import subprocess

# In and output file paths
in_csv = '../data/my_large.csv'
out_sqlite = '../data/my.sqlite'

table_name = 'my_table' # name for the SQLite database table
chunksize = 100000 # number of lines to process at each iteration

# columns that should be read from the CSV file
columns = ['molecule_id','charge','db','drugsnow','hba','hbd','loc','nrb','smiles']

# Get number of lines in the CSV file
nlines = subprocess.check_output('wc -l %s' % in_csv, shell=True)
nlines = int(nlines.split()[0]) 

# connect to database
cnx = sqlite3.connect(out_sqlite)

# Iteratively read CSV and dump lines into the SQLite table
for i in range(0, nlines, chunksize):

    df = pd.read_csv(in_csv,  
            header=None,  # no header, define column header manually later
            nrows=chunksize, # number of rows to read at each iteration
            skiprows=i)   # skip rows that were already read

    # columns to read        
    df.columns = columns

    sql.to_sql(df, 
                name=table_name, 
                con=cnx, 
                index=False, # don't use CSV file index
                index_label='molecule_id', # use a unique column from DataFrame as index
                if_exists='append') 
cnx.close()    

4
มีประโยชน์อย่างยิ่งในการดูกรณีการใช้งานที่เป็นจริงสำหรับคุณลักษณะการอ่านแบบแยกส่วน ขอบคุณ.
Alex Kestner

5
เพียงแค่คำพูดเล็ก ๆ กับหัวข้อนี้เก่า: pandas.read_csvผลตอบแทนโดยตรง (อย่างน้อยในรุ่นฉันกำลังใช้) ความ iterator ถ้าคุณเพียงแค่ให้และiterator=True chunksize=chunksizeดังนั้นคุณจะทำแบบforวนซ้ำในการpd.read_csvโทรแทนที่จะสร้างอินสแตนซ์ใหม่ทุกครั้ง อย่างไรก็ตามค่าใช้จ่ายนี้มีค่าใช้จ่ายในการโทรเท่านั้นอาจไม่มีผลกระทบที่สำคัญ
Joël

1
สวัสดี Joel ขอบคุณสำหรับหมายเหตุ! iterator=Trueและchunksizeพารามิเตอร์ที่มีอยู่แล้วกลับมาแล้วถ้าผมจำไม่ผิด อาจมีข้อผิดพลาดในเวอร์ชันเก่าซึ่งทำให้หน่วยความจำระเบิด - ฉันจะลองอีกครั้งในครั้งต่อไปที่ฉันอ่าน DataFrame ขนาดใหญ่ใน Pandas (ตอนนี้ฉันใช้ Blaze เป็นส่วนใหญ่สำหรับงานดังกล่าว)

6

ด้านล่างนี้คือขั้นตอนการทำงานของฉัน

import sqlalchemy as sa
import pandas as pd
import psycopg2

count = 0
con = sa.create_engine('postgresql://postgres:pwd@localhost:00001/r')
#con = sa.create_engine('sqlite:///XXXXX.db') SQLite
chunks = pd.read_csv('..file', chunksize=10000, encoding="ISO-8859-1",
                     sep=',', error_bad_lines=False, index_col=False, dtype='unicode')

ขึ้นอยู่กับขนาดไฟล์ของคุณคุณควรปรับขนาดให้เหมาะสมที่สุด

 for chunk in chunks:
        chunk.to_sql(name='Table', if_exists='append', con=con)
        count += 1
        print(count)

หลังจากมีข้อมูลทั้งหมดในฐานข้อมูลคุณสามารถค้นหาสิ่งที่คุณต้องการจากฐานข้อมูล


3

หากคุณต้องการโหลดไฟล์ csv ขนาดใหญ่ dask อาจเป็นตัวเลือกที่ดี มันเลียนแบบ api ของแพนด้าดังนั้นมันจึงค่อนข้างคล้ายกับแพนด้า

ลิงค์ไปยัง dask บน github


ขอบคุณตั้งแต่ฉันโพสต์สิ่งนี้ฉันใช้ dask และรูปแบบปาร์เก้
Zelazny7

1

คุณสามารถใช้ Pytable แทนแพนด้า df ออกแบบมาสำหรับชุดข้อมูลขนาดใหญ่และรูปแบบไฟล์อยู่ใน hdf5 ดังนั้นเวลาในการประมวลผลจึงค่อนข้างเร็ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.