Большой постоянный DataFrame в пандах


93

Я изучаю возможность перехода на python и pandas как давний пользователь SAS.

Однако при выполнении некоторых тестов сегодня я был удивлен, что python исчерпал память при попытке pandas.read_csv()создать csv-файл размером 128 МБ. В нем было около 200 000 строк и 200 столбцов, в основном числовых данных.

С помощью SAS я могу импортировать CSV-файл в набор данных SAS, и он может быть размером с мой жесткий диск.

Есть что-то аналогичное в pandas?

Я регулярно работаю с большими файлами и не имею доступа к распределенной вычислительной сети.


Я не знаком с пандами, но вы можете просмотреть итерацию файла. pandas.pydata.org/pandas-docs/stable/…
монкут,

Ответы:


80

В принципе, не должно быть нехватки памяти, но в настоящее время существуют проблемы с памятью read_csvдля больших файлов, вызванные некоторыми сложными внутренними проблемами Python (это расплывчато, но известно уже давно: http://github.com/pydata / pandas / issues / 407 ).

На данный момент нет идеального решения (вот утомительное: вы могли бы построчно транскрибировать файл в заранее выделенный массив NumPy или файл с отображением памяти - np.mmap), но над ним я буду работать в ближайшее время. Другое решение - читать файл более мелкими частями (использовать iterator=True, chunksize=1000), а затем объединять их с pd.concat. Проблема возникает, когда вы помещаете весь текстовый файл в память одним большим куском.


1
Скажем, я могу прочитать файл и объединить их все в один DataFrame. Должен ли DataFrame находиться в памяти? С SAS я могу работать с наборами данных любого размера, если у меня есть место на жестком диске. То же самое и с DataFrames? У меня сложилось впечатление, что они ограничены оперативной памятью, а не местом на жестком диске. Извините за вопрос о новичках и спасибо за помощь. Мне нравится твоя книга.
Zelazny7

3
Правильно, вы ограничены оперативной памятью. SAS действительно имеет гораздо лучшую поддержку обработки больших данных "вне ядра".
Wes McKinney

5
@WesMcKinney Эти обходные пути больше не понадобятся из-за нового загрузчика csv, который вы использовали в 0.10, верно?
Габриэль Грант

81

Уэс, конечно, прав! Я просто пытаюсь предоставить более полный пример кода. У меня была такая же проблема с файлом 129 Мб, которую решили:

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)?
Энди Хейден

@smci Попробовал быстро с теми же данными повторить x4 (550 Мб) или x8 (1,1 Гб). Интересно, что с или без [x for x in tp] x4 прошел нормально, а x8 вылетел из-за ошибки MemoryError.
fickludd

3
Я получаю эту ошибку при ее использовании: AssertionError: first argument must be a list-like of pandas objects, you passed an object of type "TextFileReader". Есть идеи, что здесь происходит?
Принц Кумар

3
Эта ошибка будет исправлена ​​в версии 0.14 (скоро релиз), github.com/pydata/pandas/pull/6941 ; обходной путь для <0.14.0 должен сделатьpd.concat(list(tp), ignore_index=True)
Джефф

1
что, если значения являются строковыми или категориальными - я получаю сообщение об ошибке: несовместимые категории в категориальном
конкатенации

41

Это старый поток, но я просто хотел сбросить здесь свое обходное решение. Сначала я попробовал chunksizeпараметр (даже с довольно маленькими значениями, например 10000), но это не сильно помогло; остались технические проблемы с объемом памяти (мой CSV был ~ 7,5 Гб).

Прямо сейчас я просто читаю куски CSV-файлов в цикле for и добавляю их, например, в базу данных 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=Trueи chunksize=chunksize. Следовательно, вы просто выполняете forцикл по pd.read_csvвызову вместо того, чтобы каждый раз повторно создавать его экземпляр. Однако это стоит только накладных расходов на вызовы, возможно, нет значительного влияния.
Joël

1
Привет, Джоэл. Спасибо за замечание! Параметры 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')

Исходя из размера вашего файла, вам лучше оптимизировать chunksize.

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

После того, как все данные будут в базе данных, вы можете запросить нужные из базы данных.


3

Если вы хотите загружать огромные файлы csv, dask может быть хорошим вариантом. Он имитирует api pandas, поэтому очень похож на pandas

ссылка на dask на github


Спасибо, так как я разместил это, я использую dask и формат паркета.
Zelazny7 09

1

Вы можете использовать Pytable, а не pandas df. Он предназначен для больших наборов данных, а формат файла - hdf5. Таким образом, время обработки относительно невелико.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.