Поляры против панд: разница в размерах и скорости

У меня есть файл 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 столбцов:

  • i64
  • ул
  • структура[7]
  • str (для всех остальных)

Как уже упоминалось: в столбце «content» хранятся большие тексты (от 1 до 20 страниц текста), которые мне нужно предварительно обработать и хранить по-разному, я думаю.

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

Всякий раз, когда размер записи превышает миллион, я использую Pyspark, в других случаях всегда Pandas.

Tornike Kharitonishvili 22.02.2023 10:12

Что df.memory_usage(deep=True) говорит в пандах?

Michel de Ruiter 22.02.2023 10:17
df.memory_usage(deep=True).sum() приводит к 9710410625. Так что я думаю, что .info() не был эквивалентом. Но все же панды намного быстрее.
FredMaster 22.02.2023 10:19

Вы включили время, необходимое для загрузки данных в память? Polars использует ленивую оценку и загружает данные только при необходимости. Попробуйте использовать scan_parquet(..).filter(..) и сравните необходимое время с полной загрузкой и временем обработки в пандах.

Panagiotis Kanavos 22.02.2023 10:53

Время вкл. загрузка в память у обоих примерно одинаковая (ок. 1 Минута). Я использую pl.scan_parquet(...).filter(...).collect() для поляров.

FredMaster 22.02.2023 11:01

Привет @FredMaster, а что, если вы установите столбец как категориальный перед запуском фильтра? df = df.with_columns(pl.col('type').cast(pl.Categorical))

Luca 22.02.2023 11:54

Привет @Лука. У меня была очень похожая мысль пару минут назад. К сожалению, это не сильно влияет на время вычислений. На самом деле мне было интересно, не подходят ли поляры для столбцов с большими фрагментами текста?

FredMaster 22.02.2023 12:12

Можете ли вы показать свой код для поляров и панд? Возможно, вы сравниваете яблоки с апельсинами.

ritchie46 22.02.2023 14:25

Привет @ Ричи46. Я только что обновил исходный пост. Это помогает?

FredMaster 22.02.2023 15:53
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
9
100
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Первым моим подозрением было это которое написал автор 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 22.02.2023 15:55

@FredMaster, если вы запустите мой тест, ваши поляры будут работать быстрее, чем панды?

Dean MacGregor 22.02.2023 16:12

Да, поляры примерно в 3-4 раза быстрее. Но, конечно, я мог бы оптимизировать часть панд, например. dfpd[dfpd['a'].isin(['apple','banana'])] что снижает преимущество поляров в скорости.

FredMaster 22.02.2023 16:15

у поляров тоже есть isin, просто он is_in

Dean MacGregor 22.02.2023 16:22
Ответ принят как подходящий

Как уже упоминалось: в столбце «контент» хранятся большие тексты (от 1 до 20 страниц текста), которые мне нужно предварительно обработать и хранить по-разному, я думаю.

Здесь поляры должны выполнять гораздо больше работы, чем панды. Polars использует формат памяти arrow для строковых данных. Когда вы фильтруете свой DataFrame, все столбцы воссоздаются для того, где mask оценивается как true.

Это означает, что все текстовые байты в строковых столбцах необходимо перемещать. В то время как для панд они могут просто перемещать указатели на объекты python, например. несколько байт.

Это вредно только в том случае, если у вас действительно большие значения в виде строк. Например. например, когда вы сохраняете целые веб-страницы. Вы можете ускорить это, преобразовав в категориальные.

Хорошо понял. Поэтому я учитываю это при использовании поляров. В общем, библиотека меня очень впечатлила. Отличная работа!

FredMaster 22.02.2023 16:44

Другие вопросы по теме