Эффективно читайте CSV частями с полярами (с ограниченной доступной оперативной памятью)Python

Программы на Python
Anonymous
 Эффективно читайте CSV частями с полярами (с ограниченной доступной оперативной памятью)

Сообщение Anonymous »

Я пытаюсь прочитать большой CSV-файл (приблизительно 6,4 ГБ) на небольшом компьютере (небольшой ноутбук с ОС Windows и 8 ГБ ОЗУ) перед сохранением его в базе данных SQLite (я знаю, что есть альтернативы, но дело здесь не в этом).
В случае необходимости файл, который я использую, можно найти на этой странице; на вкладке «Fichiers» оно должно быть помечено «Sirene : Fichier StockEtablissementHistorique [...]». Сегодня этот файл имеет длину около 37 миллионов строк.
Будучи большим поклонником панд, я, тем не менее, решил попробовать поляры, которые в те дни широко рекламировались.
Выведенный фрейм данных также следует соединить с другим, созданным с помощью pl.read_database (который создает pl.DataFrame и нет pl.LazyFrame).
  • Моя первая попытка включала LazyFrame и (наивную) надежду, что scan_csv с аргументом low_memory будет достаточно для обработки потребления оперативной памяти. Мой компьютер полностью завис из-за чрезмерного потребления оперативной памяти.
  • Я попробовал еще раз, используя n_rows вместе с Skip_rows_after_header. Но если

    Код: Выделить всё

    pl.read_csv(my_path, n_rows=1_000_000)
    работает нормально, pl.read_csv(my_path, n_rows=1_000_000,skip_rows_after_header=30_000_000), похоже, занимает вечность (гораздо больше, чем простой цикл для определения количества строк).
  • Я также пробовал pl.read_csv_batched, но кажется также потребуется вечность (возможно, для вычисления тех первых статистических данных, не описанных в документации).
  • Единственный способ, который я нашел для полной обработки файла с полярами, - это обрабатывать фрагменты из LazyFrame и собирать их. Примерно так:

    Код: Выделить всё

    df = (
    pl.scan_csv(
    url,
    separator=",",
    encoding="utf8",
    infer_schema_length=0,
    low_memory=True,
    )
    .lazy()
    .select(pl.col(my_cols)
    # do some more processing, for instance
    .filter(pl.col("codePaysEtrangerEtablissement").is_null())
    )
    chunksize=1_000_000
    for k in range(max_iterations:)
    chunk = df.slice(chunksize*k, chunksize).collect()
    chunk = chunk.join(my_other_dataframe, ... )
    # Do some more things like storing the chunk in a database.
    
    Это «решение», кажется, обрабатывает память, но работает очень медленно.
Я нашел другое решение, которое, кажется, работает хорошо (которое я опубликую в качестве предварительного ответа), но использует pandas read_csv с chunksize.
Это настолько хорошо, насколько это возможно, и работает только потому, что (к счастью) в нем не задействована группировка мой процесс.
Я почти уверен, что должен быть более простой «чистый полярный» способ продолжить.

РЕДАКТИРОВАТЬ
Другой фрейм данных, упомянутый здесь (

Код: Выделить всё

my_other_dataframe
в примере кода) мал. Это кадр данных длиной около 36 тыс. строк, который строго используется для преобразования поля «codeCommuneEtablissement» из его пятидлинной строки в первичный ключ целых чисел, который хранится в другой таблице. Я упомянул об этом в приведенном здесь примере, чтобы объяснить, почему вам нужно было собрать фрейм данных раньше, поскольку вы не можете объединить LazyFrame и DataFrame.

Подробнее здесь: https://stackoverflow.com/questions/763 ... ilable-ram

Вернуться в «Python»