Последовательное чтение огромного файла CSV в python

У меня есть CSV файл 10gb, содержащий некоторую информацию, которую мне нужно использовать.

Поскольку у меня ограниченная память на моем ПК, я не могу прочитать весь файл в памяти в одной партии. Вместо этого я хотел бы итеративно читать только несколько строк этого файла.

Скажем, что на первой итерации я хочу прочитать первые 100, а на втором - от 101 до 200 и т.д.

Есть ли эффективный способ выполнения этой задачи в Python? May Pandas предоставить что-то полезное для этого? Или есть лучшие (с точки зрения памяти и скорости) методы?

Ответ 1

Вот короткий ответ.

chunksize = 10 ** 6
for chunk in pd.read_csv(filename, chunksize=chunksize):
    process(chunk)

Вот очень длинный ответ.

Чтобы начать работу, вам нужно импортировать pandas и sqlalchemy. Ниже приведены команды ниже.

import pandas as pd
from sqlalchemy import create_engine

Затем установите переменную, указывающую на ваш файл csv. Это не обязательно, но это помогает в повторном использовании.

file = '/path/to/csv/file'

С этими тремя строками кода мы готовы начать анализ наших данных. Давайте посмотрим на "главу файла csv", чтобы увидеть, как будет выглядеть содержимое.

print pd.read_csv(file, nrows=5)

Эта команда использует команду pandas "read_csv" для чтения только в 5 строках (nrows = 5), а затем печатает эти строки на экране. Это позволяет вам понять структуру файла csv и убедиться, что данные отформатированы таким образом, который имеет смысл для вашей работы.

Прежде чем мы сможем действительно работать с данными, нам нужно что-то сделать с ним, чтобы мы могли начать его фильтровать для работы с подмножествами данных. Обычно я использую pandas dataframe, но с большими файлами данных нам нужно хранить данные где-то в другом месте. В этом случае хорошо настройте локальную базу данных sqlite, прочитайте файл csv в кусках, а затем напишите эти фрагменты в sqllite.

Для этого сначала нужно создать базу данных sqlite, используя следующую команду.

csv_database = create_engine('sqlite:///csv_database.db')

Далее нам нужно выполнить итерацию через CSV файл в кусках и сохранить данные в sqllite.

chunksize = 100000
i = 0
j = 1
for df in pd.read_csv(file, chunksize=chunksize, iterator=True):
      df = df.rename(columns={c: c.replace(' ', '') for c in df.columns}) 
      df.index += j
      i+=1
      df.to_sql('table', csv_database, if_exists='append')
      j = df.index[-1] + 1

С помощью этого кода мы устанавливаем chunksize на 100 000, чтобы сохранить размер управляемых блоков, инициализируя пару итераторов (i = 0, j = 0), а затем запускаем цикл for через цикл. Цикл for считывает фрагмент данных из файла CSV, удаляет пробел из любого имени столбца, а затем сохраняет фрагмент в базу данных sqlite (df.to_sql (...)).

Это может занять некоторое время, если ваш CSV файл достаточно велик, но затраченное на него время стоит того, потому что теперь вы можете использовать инструменты pandas 'sql для извлечения данных из базы данных, не беспокоясь о ограничениях памяти.

Чтобы получить доступ к данным сейчас, вы можете запускать такие команды, как:

df = pd.read_sql_query('SELECT * FROM table', csv_database)

Конечно, использование 'select *... будет загружать все данные в память, что является проблемой, с которой мы пытаемся уйти, поэтому вы должны бросить из фильтров в свои операторы select для фильтрации данных. Например:

df = pd.read_sql_query('SELECT COl1, COL2 FROM table where COL1 = SOMEVALUE', csv_database)

Ответ 3

Метод для передачи огромного CSV в базу данных хорош, потому что мы можем легко использовать SQL-запрос. Мы также должны принять во внимание две вещи.

ПЕРВЫЙ ПУНКТ: SQL также не является резиной, он не сможет растянуть память.

Например, преобразован в bd файл:

https://nycopendata.socrata.com/Social-Services/311-Service-Requests- с 2010 по настоящее время /erm2-nwe9

Для этого файла базы данных язык SQL:

pd.read_sql_query("SELECT * FROM 'table'LIMIT 600000", Mydatabase)

Он может считывать максимум около 0,6 млн. записей не более с 16 ГБ оперативной памяти ПК (время работы 15,8 секунды). Может быть злонамеренно добавить, что загрузка непосредственно из CSV файла более эффективна:

giga_plik = 'c:/1/311_Service_Requests_from_2010_to_Present.csv'
Abdul = pd.read_csv(giga_plik, nrows=1100000)

(время работы 16,5 секунды)

ВТОРАЯ ТОЧКА: Чтобы эффективно использовать серии данных SQL, преобразованные из CSV, мы должны вспомнить о подходящей форме даты. Так что я предлагаю добавить к ryguy72 код этого:

df['ColumnWithQuasiDate'] = pd.to_datetime(df['Date'])

Весь код для файла 311 примерно такой же, как я указал:

start_time = time.time()
### sqlalchemy create_engine
plikcsv = 'c:/1/311_Service_Requests_from_2010_to_Present.csv'
WM_csv_datab7 = create_engine('sqlite:///C:/1/WM_csv_db77.db')
#----------------------------------------------------------------------
chunksize = 100000 
i = 0
j = 1
## --------------------------------------------------------------------
for df in pd.read_csv(plikcsv, chunksize=chunksize, iterator=True, encoding='utf-8', low_memory=False):
      df = df.rename(columns={c: c.replace(' ', '') for c in df.columns}) 
## -----------------------------------------------------------------------
      df['CreatedDate'] = pd.to_datetime(df['CreatedDate'])  # to datetimes
      df['ClosedDate'] = pd.to_datetime(df['ClosedDate'])
## --------------------------------------------------------------------------
      df.index += j
      i+=1
      df.to_sql('table', WM_csv_datab7, if_exists='append')
      j = df.index[-1] + 1
print(time.time() - start_time)

В конце я хотел бы добавить: преобразование файла CSV напрямую из Интернета в базу данных кажется мне плохой идеей. Предлагаю скачать базу и конвертировать локально.

Ответ 4

Этот код может помочь вам в этой задаче. Он перемещается по большому CSV файлу и не занимает много памяти, так что вы можете выполнить это в стандартном ноутбуке.

import pandas as pd
import os

Здесь chunksize указывает количество строк в файле csv, которое вы хотите прочитать позже

chunksize2 = 2000

path = './'
data2 = pd.read_csv('ukb35190.csv',
                chunksize=chunksize2,
                encoding = "ISO-8859-1")
df2 = data2.get_chunk(chunksize2)
headers = list(df2.keys())
del data2

start_chunk = 0
data2 = pd.read_csv('ukb35190.csv',
                chunksize=chunksize2,
                encoding = "ISO-8859-1",
                skiprows=chunksize2*start_chunk)

заголовки = []

for i, df2 in enumerate(data2):
try:

    print('reading cvs....')
    print(df2)
    print('header: ', list(df2.keys()))
    print('our header: ', headers)

    # Access chunks within data

    # for chunk in data:

    # You can now export all outcomes in new csv files
    file_name = 'export_csv_' + str(start_chunk+i) + '.csv'
    save_path = os.path.abspath(
        os.path.join(
            path, file_name
        )
    )
    print('saving ...')

except Exception:
    print('reach the end')
    break