У меня есть файл parquet
(~ 1,5 ГБ), который я хочу обработать с помощью polars
. Полученный фрейм данных имеет 250 тыс. строк и 10 столбцов. В одном столбце большие куски текста.
Я только начал пользоваться полярами, так как слышал о них много хорошего. Одним из них является то, что он значительно быстрее, чем pandas.
Вот моя проблема / вопрос:
Предварительная обработка фрейма данных довольно медленная, поэтому я начал сравнивать с pandas
. Я делаю что-то не так или поляры для этого конкретного варианта использования просто медленнее? Если да: есть ли способ ускорить это?
Вот мой код в polars
import polars as pl
df = (pl.scan_parquet("folder/myfile.parquet")
.filter((pl.col("type")= = "Urteil") | (pl.col("type")= = "Beschluss"))
.collect()
)
df.head()
Весь код занимает примерно 1 минуту, тогда как только часть фильтрации занимает около 13 секунд.
Мой код в pandas
:
import pandas as pd
df = (pd.read_parquet("folder/myfile.parquet")
.query("type == 'Urteil' | type == 'Beschluss'") )
df.head()
Весь код также занимает примерно 1 минуту, тогда как только часть запроса занимает менее 1 секунды.
Фрейм данных имеет следующие типы для 10 столбцов:
Как уже упоминалось: в столбце «content
» хранятся большие тексты (от 1 до 20 страниц текста), которые мне нужно предварительно обработать и хранить по-разному, я думаю.
Обновлено: удалена часть размера исходного сообщения, так как сравнение не было похожим на подобное и, похоже, не связано с моим вопросом.
Что df.memory_usage(deep=True)
говорит в пандах?
df.memory_usage(deep=True).sum()
приводит к 9710410625
. Так что я думаю, что .info()
не был эквивалентом. Но все же панды намного быстрее.
Вы включили время, необходимое для загрузки данных в память? Polars использует ленивую оценку и загружает данные только при необходимости. Попробуйте использовать scan_parquet(..).filter(..)
и сравните необходимое время с полной загрузкой и временем обработки в пандах.
Время вкл. загрузка в память у обоих примерно одинаковая (ок. 1 Минута). Я использую pl.scan_parquet(...).filter(...).collect()
для поляров.
Привет @FredMaster, а что, если вы установите столбец как категориальный перед запуском фильтра? df = df.with_columns(pl.col('type').cast(pl.Categorical))
Привет @Лука. У меня была очень похожая мысль пару минут назад. К сожалению, это не сильно влияет на время вычислений. На самом деле мне было интересно, не подходят ли поляры для столбцов с большими фрагментами текста?
Можете ли вы показать свой код для поляров и панд? Возможно, вы сравниваете яблоки с апельсинами.
Привет @ Ричи46. Я только что обновил исходный пост. Это помогает?
Первым моим подозрением было это которое написал автор Polars.
Polars выполняет дополнительную работу по фильтрации строковых данных, которая в данном случае того не стоит. Polars использует большие стрелочные буферы utf8 для своих строковых данных. Это делает фильтрацию более дорогой, чем фильтрация строк/символов Python (например, указатели или байты u8).
Тогда я сделал следующее...
import polars as pl
import time
import numpy as np
num_rows=20000000
df=pl.DataFrame({'a':np.random.choice(
['apple','banana','carrot','date','eggplant'], num_rows),
'b':np.random.rand(num_rows),
'c':np.random.rand(num_rows),
'd':np.random.rand(num_rows)})
%%timeit
df.filter((pl.col('a')=='apple') | (pl.col('a')=='banana'))
# 453 ms ± 39.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
import pandas as pd
dfpd=df.to_pandas()
%%timeit
dfpd.query("a=='apple' | a=='banana'")
# 2.25 s ± 64.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Мой pl.show_versions
:
---Version info---
Polars: 0.16.2
Index type: UInt32
Platform: Linux-5.10.102.1-microsoft-standard-WSL2-x86_64-with-glibc2.35
Python: 3.10.9 | packaged by conda-forge | (main, Feb 2 2023, 20:20:04) [GCC 11.3.0]
---Optional dependencies---
pyarrow: 11.0.0
pandas: 1.5.3
numpy: 1.23.5
fsspec: 2023.1.0
connectorx: 0.3.1
xlsx2csv: 0.8.1
deltalake: <not installed>
matplotlib: 3.6.3
Спасибо за Ваш ответ. Мой вывод: polars обычно не медленнее, чем pandas, при фильтрации столбца, содержащего str. Так что, возможно, я делаю что-то не так.
@FredMaster, если вы запустите мой тест, ваши поляры будут работать быстрее, чем панды?
Да, поляры примерно в 3-4 раза быстрее. Но, конечно, я мог бы оптимизировать часть панд, например. dfpd[dfpd['a'].isin(['apple','banana'])]
что снижает преимущество поляров в скорости.
у поляров тоже есть isin, просто он is_in
Как уже упоминалось: в столбце «контент» хранятся большие тексты (от 1 до 20 страниц текста), которые мне нужно предварительно обработать и хранить по-разному, я думаю.
Здесь поляры должны выполнять гораздо больше работы, чем панды. Polars использует формат памяти arrow
для строковых данных. Когда вы фильтруете свой DataFrame
, все столбцы воссоздаются для того, где mask
оценивается как true
.
Это означает, что все текстовые байты в строковых столбцах необходимо перемещать. В то время как для панд они могут просто перемещать указатели на объекты python, например. несколько байт.
Это вредно только в том случае, если у вас действительно большие значения в виде строк. Например. например, когда вы сохраняете целые веб-страницы. Вы можете ускорить это, преобразовав в категориальные.
Хорошо понял. Поэтому я учитываю это при использовании поляров. В общем, библиотека меня очень впечатлила. Отличная работа!
Всякий раз, когда размер записи превышает миллион, я использую Pyspark, в других случаях всегда Pandas.