#pandas #gems
Не так-то просто использовать .isin в пандас сразу для нескольких полей. Единственное, что работает, это кортежи, списком не выйдет:
Не так-то просто использовать .isin в пандас сразу для нескольких полей. Единственное, что работает, это кортежи, списком не выйдет:
df[df[['DEVICE', 'READING']].apply(tuple, axis = 1).isin([('DEV1', 'READ1'), ('DEV1', 'READ2'), ('DEV2','READ1')])]
Stack Overflow
Pandas isin with multiple columns
I want to select all rows in a dataframe which contain values defined in a list.
I've got two approaches which both do not work as expected/wanted.
My dataframe looks something like this:
Timestamp
I've got two approaches which both do not work as expected/wanted.
My dataframe looks something like this:
Timestamp
#pandas
Вот говорят, мол, пандас, взрослый мощный фреймворк, опенсорс, все дела.
Но попробуйте применить к датафрейму .query по полю с мультииндексом, окажется, что в общем случае нет способа это сделать. Запрос висит на гитхабе в открытом статусе с 2016. "Что это, глупость или предательство?"
Вот говорят, мол, пандас, взрослый мощный фреймворк, опенсорс, все дела.
Но попробуйте применить к датафрейму .query по полю с мультииндексом, окажется, что в общем случае нет способа это сделать. Запрос висит на гитхабе в открытом статусе с 2016. "Что это, глупость или предательство?"
Stack Overflow
How to use pandas query() to correctly reference multiindex column headers in the query expression?
With a simple (single-level) column index one can access a column in a pandas DataFrame using .query() as follows:
df1 = pd.DataFrame(np.random.rand(10,2),index=range(10),columns=['A','B'])
df1.qu...
df1 = pd.DataFrame(np.random.rand(10,2),index=range(10),columns=['A','B'])
df1.qu...
#pandas #bollocks
Самая раздражающая штука в пандас - реализация проверки на пустой объект. Какой идиот принял такое решение, ломающее совместимость со всем остальным питоном? Постоянно на этом спотыкаюсь.
То же самое в np.array, к сожалению
И ещё bool(np.nan)=bool(pd.NA)=True
Самая раздражающая штука в пандас - реализация проверки на пустой объект. Какой идиот принял такое решение, ломающее совместимость со всем остальным питоном? Постоянно на этом спотыкаюсь.
if features:
File "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py", line 1466, in __nonzero__
raise ValueError(
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
P.S.:То же самое в np.array, к сожалению
И ещё bool(np.nan)=bool(pd.NA)=True
#pandas #optimization #bollocks
Пытаюсь выяснить, как передать большой фрейм пандас для чтения в другие процессы с помощью joblib без сериализации и копирования памяти. С массивом нумпай это сделать можно с помощью memmapping, пример есть в доке joblib, и это реально работает (память выделяется 1 раз, сериализации нет. правда, приходится один раз сдампить массив на диск). А вот с фреймом не прокатывает. Вроде оказывается, фрейм вообще нельзя инициализировать из общей памяти без копирования.
Набрёл на дискуссию, где человек приводит аргументы, что копирование излишне и вызывает пенальти к производительности. А 2 мудака-разраба пандас ему затирают про premature optimizaion. Cмотрю, у одного мудака знакомый ник. jreback. И вспоминаю, что это же существо из ядерных разрабов панадаса и мне когда-то давно писало про premature optimization, когда я спрашивал, почему какая-то операция была реализована без inplace (у меня была забита вся память и операция присваиванием просто не проходила).
Отсюда 2 вопроса:
1) кто знает техническое решение, напишите
2) почему подобные мудаки идут разрабатывать библиотеки для работы с данными, в том числе, большими данными? и потом херят все разумные начинания. так вот почему пандас такой сука медленный. вовсе не потому, что высокий уровень абстракции, гибкость. Просто разрабы - мудаки, которые под предлогом no premature optimization делают no optimization at all.
Пытаюсь выяснить, как передать большой фрейм пандас для чтения в другие процессы с помощью joblib без сериализации и копирования памяти. С массивом нумпай это сделать можно с помощью memmapping, пример есть в доке joblib, и это реально работает (память выделяется 1 раз, сериализации нет. правда, приходится один раз сдампить массив на диск). А вот с фреймом не прокатывает. Вроде оказывается, фрейм вообще нельзя инициализировать из общей памяти без копирования.
Набрёл на дискуссию, где человек приводит аргументы, что копирование излишне и вызывает пенальти к производительности. А 2 мудака-разраба пандас ему затирают про premature optimizaion. Cмотрю, у одного мудака знакомый ник. jreback. И вспоминаю, что это же существо из ядерных разрабов панадаса и мне когда-то давно писало про premature optimization, когда я спрашивал, почему какая-то операция была реализована без inplace (у меня была забита вся память и операция присваиванием просто не проходила).
Отсюда 2 вопроса:
1) кто знает техническое решение, напишите
2) почему подобные мудаки идут разрабатывать библиотеки для работы с данными, в том числе, большими данными? и потом херят все разумные начинания. так вот почему пандас такой сука медленный. вовсе не потому, что высокий уровень абстракции, гибкость. Просто разрабы - мудаки, которые под предлогом no premature optimization делают no optimization at all.
GitHub
No way to construct mixed dtype DataFrame without total copy, proposed solution · Issue #9216 · pandas-dev/pandas
After hours of tearing my hair, I've come to the conclusion that it is impossible to create a mixed dtype DataFrame without copying all of its data in. That is, no matter what you do, if you wa...
#pandas #optimization #joblib #numpy #memmap
Хорошие новости! после экспериментов выяснилось, что в последних версиях joblib умеет дампить в общую память не просто отдельные массивы numpy, а (что не указано в доке) и целиком фреймы пандас!
И даже не обязательно прописывать операции вручную. Достаточно просто передать фрейм в конструктор Parallel joblib-a как параметр, и, если он больше max_nbytes, joblib его автоматически сдампит и правильно загрузит уже в рабочих процессах! Советую в качестве temp_folder указывать быстрый NVME SSD диск, типа Parallel(n_jobs=32,max_nbytes=0, temp_folder=r'R:\Temp' ). В моих тестах отработали по сути все базовые типы столбцов: int, float, datetime, categorical.
Единственное - проблема со сложными типами, вроде массива массивов numpy (итоговый тип object), такое не работает и включается обычная сериализация. Но этого желать было бы уж слишком нереалистично, я и так не могу себе представить, как удалось победить нерадивых программистов пандас, ведь раньше даже просто инитнуть фрейм с разнородными типами столбцов было невозможно без копирования.
Вывод: если у Вас не экзотические типы данных и есть nvme, большие фреймы в свежих версиях библиотек можно спокойно передавать как параметры, и они не буду побайтово сериализоваться, более того, RAM будет расходоваться в десятки раз экономнее.
Хорошие новости! после экспериментов выяснилось, что в последних версиях joblib умеет дампить в общую память не просто отдельные массивы numpy, а (что не указано в доке) и целиком фреймы пандас!
И даже не обязательно прописывать операции вручную. Достаточно просто передать фрейм в конструктор Parallel joblib-a как параметр, и, если он больше max_nbytes, joblib его автоматически сдампит и правильно загрузит уже в рабочих процессах! Советую в качестве temp_folder указывать быстрый NVME SSD диск, типа Parallel(n_jobs=32,max_nbytes=0, temp_folder=r'R:\Temp' ). В моих тестах отработали по сути все базовые типы столбцов: int, float, datetime, categorical.
Единственное - проблема со сложными типами, вроде массива массивов numpy (итоговый тип object), такое не работает и включается обычная сериализация. Но этого желать было бы уж слишком нереалистично, я и так не могу себе представить, как удалось победить нерадивых программистов пандас, ведь раньше даже просто инитнуть фрейм с разнородными типами столбцов было невозможно без копирования.
Вывод: если у Вас не экзотические типы данных и есть nvme, большие фреймы в свежих версиях библиотек можно спокойно передавать как параметры, и они не буду побайтово сериализоваться, более того, RAM будет расходоваться в десятки раз экономнее.
#pandas #performance #parquet #codegems
Как побыстрее прочитать много файлов данных паркет (с одной схемой) и объединить их в один фрейм данных в памяти?
Базовое решение в Pandas (работает последовательно, грузит лишь 1 ядро):
И сразу лучшие решения.
Pandas с многопоточной загрузкой:
Сработало вдвое быстрее последовательного пандас.
Polars:
На моих файлах это не сработало, т.к. у меня некоторые поля записались по-разному как float32/float64, и поларс не смог их состыковать. Запросил эту фичу. Но зато уже сработало
причем вдвое быстрее мультипоточного панадас! Грузило CPU на 100%.
Если файлы с трудом влезают в оперативку, и на слияние уже не хватает RAM, можно их сначала последовательно записать в 1 большой файл, и уже потом открыть разом (работает в 5 раз медленнее худшего из предыдущих вариантов, но не требует RAM):
Как побыстрее прочитать много файлов данных паркет (с одной схемой) и объединить их в один фрейм данных в памяти?
Базовое решение в Pandas (работает последовательно, грузит лишь 1 ядро):
df =pd.concat([pl.read_parquet(file) for file in files], ignore_index=True)
И сразу лучшие решения.
Pandas с многопоточной загрузкой:
with concurrent.futures.ThreadPoolExecutor() as executor:
df = pd.concat([future.result() for future in concurrent.futures.as_completed([executor.submit(pd.read_parquet, file) for file in files])], ignore_index=True)
Сработало вдвое быстрее последовательного пандас.
Polars:
df = pl.read_parquet( f"mask*.parquet"))
На моих файлах это не сработало, т.к. у меня некоторые поля записались по-разному как float32/float64, и поларс не смог их состыковать. Запросил эту фичу. Но зато уже сработало
df =pl.concat([pl.read_parquet(file) for file in files], how="vertical_relaxed")
причем вдвое быстрее мультипоточного панадас! Грузило CPU на 100%.
Если файлы с трудом влезают в оперативку, и на слияние уже не хватает RAM, можно их сначала последовательно записать в 1 большой файл, и уже потом открыть разом (работает в 5 раз медленнее худшего из предыдущих вариантов, но не требует RAM):
schema = pq.ParquetFile(files[0]).schema_arrow
with pq.ParquetWriter(join(datapath, "output.parquet"), schema=schema) as writer:
for file in files:
writer.write_table(pq.read_table(file, schema=schema))
GitHub
Allow passing pl.concat kwargs to pl.read_csv, read_parquet etc · Issue #12508 · pola-rs/polars
Description Correct me if I'm wrong but it seems that currently when reading files by the mask, read_csv, read_parquet etc fall with error on, say, shape mismatch, or fp32 vs fp64 dtypes mismat...
#compression #pandas
Часто бывает, что приходится джойнить много файлов: всякие там csv, parquet, feather, pickle, с текстом и без, разные типы столбцов, и не всегда понятно, какой формат выбрать для промежуточного и финального хранения данных. Уже второй раз сталкиваюсь с КРАТНОЙ разницей по времени обработки (записи, чтения) и размеру итоговых файлов, а также по использованию CPU и RAM. А значит, пришло время написать утилитку быстрого тестирования. Идея в том, чтобы отдать ей небольшой кусок основного файла, посмотреть сравнительную таблицу каждой комбинации формата/сжатия, и принять решение, в каком же формате и с какими параметрами сжатия его хранить.
https://www.youtube.com/watch?v=u4rsA5ZiTls
Часто бывает, что приходится джойнить много файлов: всякие там csv, parquet, feather, pickle, с текстом и без, разные типы столбцов, и не всегда понятно, какой формат выбрать для промежуточного и финального хранения данных. Уже второй раз сталкиваюсь с КРАТНОЙ разницей по времени обработки (записи, чтения) и размеру итоговых файлов, а также по использованию CPU и RAM. А значит, пришло время написать утилитку быстрого тестирования. Идея в том, чтобы отдать ей небольшой кусок основного файла, посмотреть сравнительную таблицу каждой комбинации формата/сжатия, и принять решение, в каком же формате и с какими параметрами сжатия его хранить.
https://www.youtube.com/watch?v=u4rsA5ZiTls
YouTube
This INCREDIBLE trick will speed up your data processes.
In this video we discuss the best way to save off data as files using python and pandas. When you are working with large datasets there comes a time when you need to store your data. Most people turn to CSV files because they are easy to share and universally…
#pandas #conventions
Нахрена такое делать? Неужели нельзя параметр path одинаково назвать было?
Нахрена такое делать? Неужели нельзя параметр path одинаково назвать было?
pandas.read_pickle(
filepath_or_buffer, compression='infer', storage_options=None)
DataFrame.to_pickle(
path, compression='infer', protocol=5, storage_options=None)
#pandas #compression
Итак, результаты бенчмарка на фрейме пандас с широким текстовым столбцом. Код в комментах.
Pandas: 2.0.3, DF size: 7.15Mb, Dtypes: {dtype('O'): 17, dtype('float64'): 2, dtype('float32'): 2, dtype('<M8[ns]'): 1}
Лучшие результаты показал пикл+xz сжатие. Наименьший итоговый размер файла, очень быстрое чтение, правда, за счёт долгой записи.
Паркетный brotli ошарашил своим экстремально долгим архивированием. Но только в реализации fastparquet! В версии pyarrow brotli оказался лучшим паркетным вариантом для моей конкретной задачи.
Итак, результаты бенчмарка на фрейме пандас с широким текстовым столбцом. Код в комментах.
benchmark_dataframe_compression(df=df, head=1000, benchmark_dir_path=r"R:\Data", nrepeats=10, verbose=True)
Pandas: 2.0.3, DF size: 7.15Mb, Dtypes: {dtype('O'): 17, dtype('float64'): 2, dtype('float32'): 2, dtype('<M8[ns]'): 1}
Лучшие результаты показал пикл+xz сжатие. Наименьший итоговый размер файла, очень быстрое чтение, правда, за счёт долгой записи.
Паркетный brotli ошарашил своим экстремально долгим архивированием. Но только в реализации fastparquet! В версии pyarrow brotli оказался лучшим паркетным вариантом для моей конкретной задачи.
Forwarded from Data Science Private Sharing
#Tip42 #EDA #Pandas
На прошлой неделе поучаствовал в хакатоне GO ALGO, организованный Московской фондовой биржей.
Для решения задачи нужно было анализировать биржевую информацию. И наконец-то мне мне удалось применить на практике очень редкий вид графиков — Спарклайны (Sparkline).
Спарклайны — это небольшие немаркированные графики. Обычно они не содержат ни осей ни подписей, поэтому в основном предназначены для передачи какой-то общей идеи.
А т.к. спарклайны очень маленькие, то они отлично помещаются в ячейках Pandas'а :)
Графики можно редактировать в определенных границах: менять их ширину/высоту, можно разукрасить на свое усмотрение. Также вы можете вывести другие типы графиков: барплоты, гистограммы и пр.
З.Ы. Сам хакатон проходил в интересном формате. С одной стороны это был обычный хактон - с чек-поинтами и общением с экспертами. С другой - он длился целых 10 дней (вместо обычных 2-3). А за это время можно было сделать неплохой продукт :)
На прошлой неделе поучаствовал в хакатоне GO ALGO, организованный Московской фондовой биржей.
Для решения задачи нужно было анализировать биржевую информацию. И наконец-то мне мне удалось применить на практике очень редкий вид графиков — Спарклайны (Sparkline).
Спарклайны — это небольшие немаркированные графики. Обычно они не содержат ни осей ни подписей, поэтому в основном предназначены для передачи какой-то общей идеи.
А т.к. спарклайны очень маленькие, то они отлично помещаются в ячейках Pandas'а :)
import base64
from io import BytesIO
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import HTML
def sparkline(data):
data = list(data)
fig, ax = plt.subplots(1, 1, figsize=(4, 0.25))
ax.plot(data)
# Убираем все лишнее с графика
ax.set_axis_off()
# Заливаем график
ax.fill_between(range(len(data)), data, len(data)*[min(data)], alpha=0.1)
# Выводим min/max
plt.plot(np.argmax(data), data[np.argmax(data)], 'r.')
plt.plot(np.argmin(data), data[np.argmin(data)], 'm.')
img = BytesIO()
plt.savefig(img)
img.seek(0)
plt.close()
return '<img src="data:image/png;base64,{}"/>'.format(base64.b64encode(img.read()).decode())
agg_df = df.groupby('tradedate', as_index=False)['pr_open'].agg(list)
agg_df['sparkline'] = agg_df['pr_open'].map(sparkline)
HTML(agg_df[['tradedate','sparkline']][-10:].to_html(escape=False))
Графики можно редактировать в определенных границах: менять их ширину/высоту, можно разукрасить на свое усмотрение. Также вы можете вывести другие типы графиков: барплоты, гистограммы и пр.
З.Ы. Сам хакатон проходил в интересном формате. С одной стороны это был обычный хактон - с чек-поинтами и общением с экспертами. С другой - он длился целых 10 дней (вместо обычных 2-3). А за это время можно было сделать неплохой продукт :)
#security #pandas #cryptography #cryptpandas
Интересно, как куски зашифрованного файла прогоняют через энтропийный анализ, чтоб уточнить алгоритмы шифрования:
"In CyberChef, we can also save the artifacts (refer to the aged-diskette icon) and it will save the file as a raw binary (sans the base64 encoding we tested it with). We then can throw that into Kali and run some tests on both the base64 version and the raw version and check to see what their entropy values are."
Вообще использование cryptpandas может быть хорошей идеей для облачных вычислений.
https://eforensicsmag.com/forensic-fun-with-cryptographic-dataframes-using-python/
Интересно, как куски зашифрованного файла прогоняют через энтропийный анализ, чтоб уточнить алгоритмы шифрования:
"In CyberChef, we can also save the artifacts (refer to the aged-diskette icon) and it will save the file as a raw binary (sans the base64 encoding we tested it with). We then can throw that into Kali and run some tests on both the base64 version and the raw version and check to see what their entropy values are."
Вообще использование cryptpandas может быть хорошей идеей для облачных вычислений.
https://eforensicsmag.com/forensic-fun-with-cryptographic-dataframes-using-python/
eForensics
Forensic Fun with Cryptographic DataFrames using Python - eForensics
This is a journey into clever and interesting ways to apply cryptographic DataFrames [1] for forensic/anti-forensic purposes using Python3. You'll learn to work with cryptographic DataFrames for interesting ulterior motives using Python3.
#polars #pandas #duckdb
Надо переходить на поларс, похоже. Ну или на уткобазу )
Особенно интересны в поларсе абстрактные выражения, стриминговый режим, поддержка тензоров pytorch и (будущая) интеграция с rapids,чтоб он считал на GPU. Это будет вааще бомба.
https://www.youtube.com/watch?v=LXz69qQVy5U
Надо переходить на поларс, похоже. Ну или на уткобазу )
Особенно интересны в поларсе абстрактные выражения, стриминговый режим, поддержка тензоров pytorch и (будущая) интеграция с rapids,чтоб он считал на GPU. Это будет вааще бомба.
https://www.youtube.com/watch?v=LXz69qQVy5U
YouTube
Михаил Архипов, Павел Цветов | Сын маминой подруги: Может ли Polars заменить Pandas?
Спикеры: Михаил Архипов, Павел Цветов, Мир Plat.Form Data Scientist, занимаемся задачами прикладного анализа больших данных и ML-разработкой в команде Центра транзакционной аналитики НСПК
Тема доклада: в рамках доклада, мы расскажем как начали использовать…
Тема доклада: в рамках доклада, мы расскажем как начали использовать…
#pandas #dask #polars
Интересное сравнительное тестирjвание, в т.ч пандаса с разными бэкендами - нампай и эрроу, + с Copy On Write. Про dask-expr я даже не знал.
https://www.youtube.com/watch?v=IGgh9Aj9qiE
Интересное сравнительное тестирjвание, в т.ч пандаса с разными бэкендами - нампай и эрроу, + с Copy On Write. Про dask-expr я даже не знал.
https://www.youtube.com/watch?v=IGgh9Aj9qiE
YouTube
Ian Ozsvald & Giles Weaver - Pandas 2, Dask or Polars? Tackling larger data on a single machine
www.pydata.org
Pandas 2 brings new Arrow data types, faster calculations and better scalability. Dask scales Pandas across cores and recently released a new "expressions" optimization for faster computations. Polars is a new competitor to Pandas designed…
Pandas 2 brings new Arrow data types, faster calculations and better scalability. Dask scales Pandas across cores and recently released a new "expressions" optimization for faster computations. Polars is a new competitor to Pandas designed…
#polars #pandas
Сравнительно недавно начал по-настоящему изучать поларс, потому что пандас уже задолбал своей неповоротливостью. Хочу поделиться некоторыми замечаниями о фреймворке.
Прежде всего, в глаза бросается жёсткая логика в наименовании методов. Наверное, если бы компьютеру поручили самому разработать фреймворк, к таким названиям как раз и пришли бы кремниевые мозги ИИ. Каждый раз, когда видишь полар-овские group_by, write_csv, кажется, как разрабы поларс со всего размаха тыкают носом страдающих слабой логикой, маразмом, и вообще очень ветреных разрабов пандас.
Какие фишки реально понравились:
Выбор столбцов.
Можно выбирать столбцы регуляркой, выбирать все столбцы одним ключевым словом, элегантно отбрасывать столбцы (в т.ч. опять же регуляркой). Этого реально не хватает в пандас, да и sql.
Ещё больше упрощают дело селекторы:
Комбинации селекторов (в терминах логики множеств) уже менее интуитивны:
Апдейты Поларс.
Их фигачат каждые чуть ли не 2 недели, причём там реальная работа, помногу. Что ж это будет за зверь через год?
И даже я сам уже запостил несколько issues, которые были приняты во внимание и исправлены (самим Риччи). Внёс свой скромный вклад в дело улучшения DS библ для всех 😅.
Многопоточное исполнение. Полная утилизация CPU. Оптимизация операций над lazy фреймами.
Это просто небо и земля, по сравнению с пандасом. Никогда для работы со сколько-нибудь серъёзным набором данных (от десятка гигов) я больше не буду использовать пандас. Получается, ты платишь за машину с сотней ядер, а с pandas используешь большую часть времени одно. Более того, уже есть поддержка engine="gpu", спасибо кодерам Nvidia (под капотом использует cudf. есть ограничения на виды операций и типы данных, которые можно исполнять на gpu, но потихоньку они снимаются).
Синтаксис операций.
Можно обращаться сразу к множеству столбцов, и элегантно применять ко всем одно преобразование. Можно писать генерики для сложной работы со столбцами, которые станут известны лишь в контексте. По сравнению с пандас, паттерн применения преобразований меняется - надо стараться вынести как можно больше операций в каждый вызов контекста (select, with_columns, group_by, group_by_dynamic), потому что так они параллелятся на все ядра. В операциях не обязательно использовать существующие столбцы, можно и просто выражения над ними! Вроде
Rust plugins.
Если какие-то операции недоступны в нативном polars, можно вызвать питоновские функции, черезе map_groups, например, но они не будут параллелиться. Для этих случаев можно написать и скомпилировать свой плагин на Расте. Я пробовал, это сложно ) В синтаксисе этого раста чёрт ногу сломит. И не одну. Но возможность есть!
Фишка которую я пока не пробовал - streaming . Работа с данными больше RAM.
Сравнительно недавно начал по-настоящему изучать поларс, потому что пандас уже задолбал своей неповоротливостью. Хочу поделиться некоторыми замечаниями о фреймворке.
Прежде всего, в глаза бросается жёсткая логика в наименовании методов. Наверное, если бы компьютеру поручили самому разработать фреймворк, к таким названиям как раз и пришли бы кремниевые мозги ИИ. Каждый раз, когда видишь полар-овские group_by, write_csv, кажется, как разрабы поларс со всего размаха тыкают носом страдающих слабой логикой, маразмом, и вообще очень ветреных разрабов пандас.
Какие фишки реально понравились:
Выбор столбцов.
Можно выбирать столбцы регуляркой, выбирать все столбцы одним ключевым словом, элегантно отбрасывать столбцы (в т.ч. опять же регуляркой). Этого реально не хватает в пандас, да и sql.
df.select(pl.col("ticker", "^.*_high$", "^.*_low$"))
df.select(pl.all().exclude("^day_.*$"))
Ещё больше упрощают дело селекторы:
import polars.selectors as cs
df.select(cs.string() | cs.ends_with("_high"))
Комбинации селекторов (в терминах логики множеств) уже менее интуитивны:
df.select(cs.contains("_") - cs.string())
,но всё равно крайне полезны.Апдейты Поларс.
Их фигачат каждые чуть ли не 2 недели, причём там реальная работа, помногу. Что ж это будет за зверь через год?
И даже я сам уже запостил несколько issues, которые были приняты во внимание и исправлены (самим Риччи). Внёс свой скромный вклад в дело улучшения DS библ для всех 😅.
Многопоточное исполнение. Полная утилизация CPU. Оптимизация операций над lazy фреймами.
Это просто небо и земля, по сравнению с пандасом. Никогда для работы со сколько-нибудь серъёзным набором данных (от десятка гигов) я больше не буду использовать пандас. Получается, ты платишь за машину с сотней ядер, а с pandas используешь большую часть времени одно. Более того, уже есть поддержка engine="gpu", спасибо кодерам Nvidia (под капотом использует cudf. есть ограничения на виды операций и типы данных, которые можно исполнять на gpu, но потихоньку они снимаются).
Синтаксис операций.
Можно обращаться сразу к множеству столбцов, и элегантно применять ко всем одно преобразование. Можно писать генерики для сложной работы со столбцами, которые станут известны лишь в контексте. По сравнению с пандас, паттерн применения преобразований меняется - надо стараться вынести как можно больше операций в каждый вызов контекста (select, with_columns, group_by, group_by_dynamic), потому что так они параллелятся на все ядра. В операциях не обязательно использовать существующие столбцы, можно и просто выражения над ними! Вроде
df.sort(pl.col("name").str.len_bytes(),descending=True)
.Rust plugins.
Если какие-то операции недоступны в нативном polars, можно вызвать питоновские функции, черезе map_groups, например, но они не будут параллелиться. Для этих случаев можно написать и скомпилировать свой плагин на Расте. Я пробовал, это сложно ) В синтаксисе этого раста чёрт ногу сломит. И не одну. Но возможность есть!
Фишка которую я пока не пробовал - streaming . Работа с данными больше RAM.
#polars #pandas
Отличия от пандас в концепциях:
Нет индексов (кроме целочисленных), осей, модификаций столбцов датафреймов inplace. Хотя на самом деле при модификации столбца фрейм в памяти не пересобирается, компилируется (быстро) лишь новый мета-объект фрейма со ссылками на те же массивы arrow.
Поларс не поддерживает разные типы данных в одном и том же столбце (кроме null), пандас поддерживает.
Пандас по умолчанию удаляет строки с отсутствующими значениями при агрегации. Поларс сохраняет все группы.
Поларс различает отсутствующие значения (null) и некорректные числа (NaN, что означает "не число"), и это различие сохраняется независимо от типа данных.
В результате этого пандас преобразует столбцы с целыми числами в столбцы с плавающей точкой при появлении отсутствующих значений (хотя этого не происходит с новыми типами данных arrow, в посл версиях). Это связано с тем, что тип Integer не поддерживает отсутствующие значения. Поларс такого преобразования не делает, так как поддерживает отсутствующие значения для всех типов данных (хранит битовую маску nulls для каждого поля).
В пандас можно иметь несколько столбцов с одинаковым именем. В Поларс имена столбцов должны быть уникальными.
Странности поларса:
nan vs null. Не уверен, что это хорошая идея. Но вполне в духе строгостей поларса.
animals_pl.unique(subset="class") вместо animals_pd.drop_duplicates(subset="class")
sort(...,descending=). Зачем было отклоняться от привычного в пандас acscending? too much.
sum_horizontal() и подобные функции (вследствие отсутствия axis).
Из интересного вам глянуть:
df.to_dict vs df.to_dicts
approx_n_unique()
glimpse()
.set_sorted()
stacking vs pl.concat vs extending
Отличия от пандас в концепциях:
Нет индексов (кроме целочисленных), осей, модификаций столбцов датафреймов inplace. Хотя на самом деле при модификации столбца фрейм в памяти не пересобирается, компилируется (быстро) лишь новый мета-объект фрейма со ссылками на те же массивы arrow.
Поларс не поддерживает разные типы данных в одном и том же столбце (кроме null), пандас поддерживает.
Пандас по умолчанию удаляет строки с отсутствующими значениями при агрегации. Поларс сохраняет все группы.
Поларс различает отсутствующие значения (null) и некорректные числа (NaN, что означает "не число"), и это различие сохраняется независимо от типа данных.
В результате этого пандас преобразует столбцы с целыми числами в столбцы с плавающей точкой при появлении отсутствующих значений (хотя этого не происходит с новыми типами данных arrow, в посл версиях). Это связано с тем, что тип Integer не поддерживает отсутствующие значения. Поларс такого преобразования не делает, так как поддерживает отсутствующие значения для всех типов данных (хранит битовую маску nulls для каждого поля).
В пандас можно иметь несколько столбцов с одинаковым именем. В Поларс имена столбцов должны быть уникальными.
Странности поларса:
nan vs null. Не уверен, что это хорошая идея. Но вполне в духе строгостей поларса.
animals_pl.unique(subset="class") вместо animals_pd.drop_duplicates(subset="class")
sort(...,descending=). Зачем было отклоняться от привычного в пандас acscending? too much.
sum_horizontal() и подобные функции (вследствие отсутствия axis).
Из интересного вам глянуть:
df.to_dict vs df.to_dicts
approx_n_unique()
glimpse()
.set_sorted()
stacking vs pl.concat vs extending
#polars #pandas #codegems
Что в поларс НЕ понравилось.
Активное переименование методов от версии к версии. Это сводит с ума все AI, которые пробуешь использовать для генерации кода.
Мало примеров в доке к сложным методам типа .over и .group_by, .group_by_dynamic. Реально непонятно, как и на каких принципах оно отработает. В документации расписано слабовато.
Иногда polars начинает жрать всю память на относительно простых операциях, где мог бы быть более экономным. Иногда проскакивают ошибки/панические атаки, зачастую сложновоспроизводимые.
И самое главное. Если у вас большие фреймы и много операций (математических, group_by), поларс отработает быстро, но гарантированно забьёт вам всю оперативку. То же сделает и пандас, но за ним неиспользованную память можно хотя бы (если повезёт) подчистить вызовом ctypes.CDLL("libc.so.6").malloc_trim(0)
Поларс же, похоже, создаёт какие-то маленькие и разбросанные в адресном пространстве арены памяти, которые таким способом не подчищаются. И вообще никаким не подчищаются, только завершением процесса. К примеру, у меня после интенсивных расчётов и джойнов фрейм в 100 гигов, а занято памяти на терабайт. И освободить её на линуксе никак нельзя, я уже и аллокаторы пробовал альтернативные типа jemalloc, tmalloc - без толку. Это я считаю большой проблемой вычислений и big data, и странно, что никого это не колышет особо. По факту сбора мусора в линукс нет, если вы не знали, ребята. По крайней мере после отработки поларса. "Спасибо" странным авторам аллокаторов памяти.
Что забавно, на винде этот вопрос решается!!! )) Используйте
и спите спокойно.
Следующая жёсткая проблема - производительность с dtype=category. Не храните паркетные файлы с этим типом данных, лучше конвертируйте в string (с compression='zstd', конечно). Иначе потом они будут склеиваться ВЕЧНОСТЬ, при любых настройках StringCache.
Что в поларс НЕ понравилось.
Активное переименование методов от версии к версии. Это сводит с ума все AI, которые пробуешь использовать для генерации кода.
Мало примеров в доке к сложным методам типа .over и .group_by, .group_by_dynamic. Реально непонятно, как и на каких принципах оно отработает. В документации расписано слабовато.
Иногда polars начинает жрать всю память на относительно простых операциях, где мог бы быть более экономным. Иногда проскакивают ошибки/панические атаки, зачастую сложновоспроизводимые.
И самое главное. Если у вас большие фреймы и много операций (математических, group_by), поларс отработает быстро, но гарантированно забьёт вам всю оперативку. То же сделает и пандас, но за ним неиспользованную память можно хотя бы (если повезёт) подчистить вызовом ctypes.CDLL("libc.so.6").malloc_trim(0)
Поларс же, похоже, создаёт какие-то маленькие и разбросанные в адресном пространстве арены памяти, которые таким способом не подчищаются. И вообще никаким не подчищаются, только завершением процесса. К примеру, у меня после интенсивных расчётов и джойнов фрейм в 100 гигов, а занято памяти на терабайт. И освободить её на линуксе никак нельзя, я уже и аллокаторы пробовал альтернативные типа jemalloc, tmalloc - без толку. Это я считаю большой проблемой вычислений и big data, и странно, что никого это не колышет особо. По факту сбора мусора в линукс нет, если вы не знали, ребята. По крайней мере после отработки поларса. "Спасибо" странным авторам аллокаторов памяти.
Что забавно, на винде этот вопрос решается!!! )) Используйте
def trim_windows_process_memory(pid: int = None) -> bool:
"""Causes effect similar to malloc_trim on -nix."""
# Define SIZE_T based on the platform (32-bit or 64-bit)
if ctypes.sizeof(ctypes.c_void_p) == 4:
SIZE_T = ctypes.c_uint32
else:
SIZE_T = ctypes.c_uint64
# Get a handle to the current process
if not pid:
pid = ctypes.windll.kernel32.GetCurrentProcess()
# Define argument and return types for SetProcessWorkingSetSizeEx
ctypes.windll.kernel32.SetProcessWorkingSetSizeEx.argtypes = [
ctypes.wintypes.HANDLE, # Process handle
SIZE_T, # Minimum working set size
SIZE_T, # Maximum working set size
ctypes.wintypes.DWORD, # Flags
]
ctypes.windll.kernel32.SetProcessWorkingSetSizeEx.restype = ctypes.wintypes.BOOL
# Define constants for SetProcessWorkingSetSizeEx
QUOTA_LIMITS_HARDWS_MIN_DISABLE = 0x00000002
# Attempt to set the working set size
result = ctypes.windll.kernel32.SetProcessWorkingSetSizeEx(pid, SIZE_T(-1), SIZE_T(-1), QUOTA_LIMITS_HARDWS_MIN_DISABLE)
if result == 0:
# Retrieve the error code
error_code = ctypes.windll.kernel32.GetLastError()
logger.error(f"SetProcessWorkingSetSizeEx failed with error code: {error_code}")
return False
else:
return True
и спите спокойно.
Следующая жёсткая проблема - производительность с dtype=category. Не храните паркетные файлы с этим типом данных, лучше конвертируйте в string (с compression='zstd', конечно). Иначе потом они будут склеиваться ВЕЧНОСТЬ, при любых настройках StringCache.
Stack Overflow
Polars DF takes up lots of RAM
I'm running a python script that analyses a dataframe (loaded from a parquet file).
I've ran my program using the memory_profiler package to see the mem signature it has - on 2 DataFrames with a si...
I've ran my program using the memory_profiler package to see the mem signature it has - on 2 DataFrames with a si...
#polars #pandas
Запостил мини-серию о polars по сравнению с pandas:
Преимущества polars
Отличия от pandas
Недостатки polars
Заключение.
Несмотря на его сыроватость, по умолчанию теперь всегда буду использовать в своих ds-проектах polars. Людям, которые пишут pandas, наплевать на производительность, я это знаю по личному общению с одним таким человеком. Их принцип Кнутовкий, premature optimization is the root of all evil, поэтому, чтобы избежать зла, они не оптимизируют вообще. С таким кредо вам не библиотеки для работы с данными писать, уважаемые. Ну вот история вас и оставляет на обочине.
Всё же, полностью от пандас отказываться неразумно, часто там определённые вещи можно закодить быстрее в силу большей гибкости (axis) или наличия индексов. Но, как правило, я pandas в этом ключе использую лишь для маленьких фреймов. Ещё он понимает больше форматов данных. И у поларса к нему есть быстрый интероп.
Так что используйте оба, но приоритет отдавайте polars. Жизнь слишком коротка, чтобы грузить лишь 1 ядро CPU из 100 )
Из новостей: компания Риччи работает над polars cloud, это будет что-то типа dask/coiled, похоже.
Запостил мини-серию о polars по сравнению с pandas:
Преимущества polars
Отличия от pandas
Недостатки polars
Заключение.
Несмотря на его сыроватость, по умолчанию теперь всегда буду использовать в своих ds-проектах polars. Людям, которые пишут pandas, наплевать на производительность, я это знаю по личному общению с одним таким человеком. Их принцип Кнутовкий, premature optimization is the root of all evil, поэтому, чтобы избежать зла, они не оптимизируют вообще. С таким кредо вам не библиотеки для работы с данными писать, уважаемые. Ну вот история вас и оставляет на обочине.
Всё же, полностью от пандас отказываться неразумно, часто там определённые вещи можно закодить быстрее в силу большей гибкости (axis) или наличия индексов. Но, как правило, я pandas в этом ключе использую лишь для маленьких фреймов. Ещё он понимает больше форматов данных. И у поларса к нему есть быстрый интероп.
Так что используйте оба, но приоритет отдавайте polars. Жизнь слишком коротка, чтобы грузить лишь 1 ядро CPU из 100 )
Из новостей: компания Риччи работает над polars cloud, это будет что-то типа dask/coiled, похоже.
Telegram
Aspiring Data Science
#polars #pandas
Сравнительно недавно начал по-настоящему изучать поларс, потому что пандас уже задолбал своей неповоротливостью. Хочу поделиться некоторыми замечаниями о фреймворке.
Прежде всего, в глаза бросается жёсткая логика в наименовании методов.…
Сравнительно недавно начал по-настоящему изучать поларс, потому что пандас уже задолбал своей неповоротливостью. Хочу поделиться некоторыми замечаниями о фреймворке.
Прежде всего, в глаза бросается жёсткая логика в наименовании методов.…