Большой, постоянный фрейм данных в панд


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

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

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

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

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

6 82

6 ответов:

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

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

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

from pandas import *

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

это более старый поток, но я просто хотел сбросить свое обходное решение здесь. Я изначально пробовал chunksize параметр (даже с довольно маленькими значениями, такими как 10000), но это не очень помогло; все еще были технические проблемы с размером памяти (мой 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()    

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

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

ниже мой рабочий поток.

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)

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

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