DataFrame besar dan persisten di panda

93

Saya menjelajahi peralihan ke python dan panda sebagai pengguna SAS lama.

Namun, ketika menjalankan beberapa tes hari ini, saya terkejut bahwa python kehabisan memori ketika mencoba pandas.read_csv()file csv 128mb. Itu memiliki sekitar 200.000 baris dan 200 kolom yang sebagian besar data numerik.

Dengan SAS, saya dapat mengimpor file csv ke dalam dataset SAS dan ukurannya bisa sebesar hard drive saya.

Apakah ada analogi pandas?

Saya secara teratur bekerja dengan file besar dan tidak memiliki akses ke jaringan komputasi terdistribusi.

Zelazny7
sumber
Saya tidak terbiasa dengan panda, tetapi Anda mungkin ingin melihat-lihat melalui file. pandas.pydata.org/pandas-docs/stable/…
monkut

Jawaban:

80

Pada prinsipnya itu tidak boleh kehabisan memori, tetapi saat ini ada masalah memori dengan read_csvpada file besar yang disebabkan oleh beberapa masalah internal Python yang kompleks (ini tidak jelas tetapi sudah diketahui sejak lama: http://github.com/pydata / pandas / issues / 407 ).

Saat ini tidak ada solusi yang tepat (ini yang membosankan: Anda dapat mentranskripsikan file baris demi baris menjadi array NumPy yang telah dialokasikan sebelumnya atau file yang dipetakan memori-- np.mmap), tetapi ini adalah solusi yang akan saya kerjakan dalam waktu dekat. Solusi lain adalah membaca file dalam potongan-potongan kecil (gunakan iterator=True, chunksize=1000) lalu gabungkan lalu dengan pd.concat. Masalahnya muncul saat Anda menarik seluruh file teks ke dalam memori dalam satu slurp besar.

Wes McKinney
sumber
1
Katakanlah saya bisa membaca file dan menggabungkan semuanya menjadi satu DataFrame. Apakah DataFrame harus berada di memori? Dengan SAS, saya dapat bekerja dengan kumpulan data dalam berbagai ukuran selama saya memiliki ruang hard drive. Apakah itu sama dengan DataFrames? Saya mendapat kesan bahwa mereka dibatasi oleh RAM dan bukan ruang hard-drive. Maaf untuk pertanyaan noob dan terima kasih atas bantuan Anda. Saya menikmati bukumu.
Zelazny7
3
Benar, Anda dibatasi oleh RAM. SAS memang memiliki dukungan yang jauh lebih baik untuk pemrosesan data besar "out-of-core".
Wes McKinney
5
@WesMcKinney Solusi ini seharusnya tidak diperlukan lagi, karena csv loader baru Anda mendarat di 0,10, bukan?
Gabriel Grant
81

Kami tentu saja benar! Saya hanya akan memberikan sedikit contoh kode yang lebih lengkap. Saya memiliki masalah yang sama dengan file 129 Mb, yang diselesaikan dengan:

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`
fickludd
sumber
6
Saya pikir Anda bisa melakukannya df = concate(tp, ignore_index=True)?
Andy Hayden
@smci Mencoba ini dengan cepat dengan data yang sama berulang x4 (550 Mb) atau x8 (1.1Gb). Menariknya, dengan atau tanpa [x untuk x di tp], x4 berjalan lancar, dan x8 mengalami crash di MemoryError.
fickludd
3
Saya mendapatkan error ini ketika menggunakannya: AssertionError: first argument must be a list-like of pandas objects, you passed an object of type "TextFileReader". Tahu apa yang terjadi di sini?
Pangeran Kumar
3
Bug ini akan diperbaiki dalam 0.14 (segera dirilis), github.com/pydata/pandas/pull/6941 ; solusi untuk <0.14.0 harus dilakukanpd.concat(list(tp), ignore_index=True)
Jeff
1
bagaimana jika nilainya adalah string atau kategorikal - saya mendapatkan kesalahan: kategori tidak kompatibel dalam concat kategoris
As3adTintin
41

Ini adalah utas yang lebih lama, tetapi saya hanya ingin membuang solusi solusi saya di sini. Saya awalnya mencoba chunksizeparameter (bahkan dengan nilai yang cukup kecil seperti 10000), tetapi tidak banyak membantu; masih memiliki masalah teknis dengan ukuran memori (CSV saya ~ 7,5 Gb).

Saat ini, saya baru saja membaca potongan file CSV dalam pendekatan for-loop dan menambahkannya misalnya, ke database SQLite langkah demi langkah:

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()    

sumber
4
Sangat berguna untuk melihat kasus penggunaan yang realistis untuk fitur membaca yang terpotong-potong. Terima kasih.
Alex Kestner
5
Hanya sedikit komentar, untuk topik lama ini: pandas.read_csvlangsung mengembalikan (setidaknya pada versi yang saya gunakan saat ini) sebuah iterator jika Anda hanya menyediakan iterator=Truedan chunksize=chunksize. Oleh karena itu, Anda hanya perlu melakukan forloop pada pd.read_csvpanggilan, alih-alih membuat instance ulang setiap saat. Namun, ini hanya biaya overhead panggilan, mungkin tidak ada dampak yang signifikan.
Joël
1
Hai, Joel. Terima kasih atas catatannya! The iterator=Truedan chunksizeparameter yang sudah ada saat itu jika saya ingat benar. Mungkin ada bug di versi lama yang menyebabkan memori meledak - Saya akan mencobanya lagi lain kali saat saya membaca DataFrame besar di Pandas (Saya kebanyakan menggunakan Blaze sekarang untuk tugas-tugas seperti itu)
6

Di bawah ini adalah alur kerja saya.

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')

Berdasarkan ukuran file Anda, Anda sebaiknya mengoptimalkan ukuran chunksize.

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

Setelah memiliki semua data dalam database, Anda bisa membuat kueri yang Anda butuhkan dari database.

BEN_YO
sumber
3

Jika Anda ingin memuat file csv yang besar, dask mungkin merupakan pilihan yang baik. Ini meniru api panda, jadi rasanya sangat mirip dengan panda

tautan untuk berjemur di github

pengguna8108173
sumber
Terima kasih, sejak saya memposting ini, saya telah menggunakan dask dan format parket.
Zelazny7
1

Anda dapat menggunakan Pytable daripada pandas df. Ini dirancang untuk kumpulan data besar dan format file dalam hdf5. Sehingga waktu pengerjaannya relatif cepat.

Elm662
sumber