Большой, постоянный DataFrame в пандах
Я изучаю возможность перехода на python и pandas как давний пользователь SAS.
Однако, выполняя некоторые тесты сегодня, я был удивлен, что питону не хватило памяти при попытке pandas.read_csv()
128 МБ CSV-файл. В нем было около 200 000 строк и 200 столбцов в основном числовых данных.
С помощью SAS я могу импортировать CSV-файл в набор данных SAS, и он может быть размером с мой жесткий диск.
Есть ли что-то аналогичное в pandas
?
Я регулярно работаю с большими файлами и не имею доступа к распределенной вычислительной сети.
6 ответов
В принципе это не должно исчерпать память, но в настоящее время есть проблемы с памятью read_csv
для больших файлов, вызванных некоторыми сложными внутренними проблемами Python (это расплывчато, но это известно давно: http://github.com/pydata/pandas/issues/407).
На данный момент не существует идеального решения (вот утомительное: вы можете транслировать файл строка за строкой в предварительно выделенный массив NumPy или файл с отображением в памяти -np.mmap
), но над этим я буду работать в ближайшее время. Другое решение состоит в том, чтобы прочитать файл более мелкими частями (используйте iterator=True, chunksize=1000
) затем соединить затем с pd.concat
, Проблема возникает, когда вы вытаскиваете весь текстовый файл в память одним большим всплеском.
Уэс, конечно, прав! Я просто добавляю немного более полного примера кода. У меня была такая же проблема с файлом 129 Мб, которая была решена с помощью:
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 Гб).
Прямо сейчас я просто читаю фрагменты CSV-файлов в циклическом подходе и постепенно добавляю их, например, в базу данных 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()
Ниже мой рабочий поток.
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)
После того, как все данные в базе данных, вы можете запросить те, которые вам нужны из базы данных.
Если вы хотите загружать огромные CSV-файлы, хорошим вариантом может быть dask. Он имитирует панды API, поэтому он очень похож на панд
Вы можете использовать Pytable вместо Pandas DF. Он предназначен для больших массивов данных, а формат файла - hdf5. Таким образом, время обработки относительно быстро.