Демонстрация использования новой невероятно быстрой библиотеки DataFrame для взаимодействия с табличными данными.

Если вы похожи на меня, вы можете слышать много шумихи об этой новой библиотеке Polars, но не знаете, что это такое и как начать работу. Если вы новичок в этом, самый простой способ понять Polars — это очень быстрая альтернатива более традиционной библиотеке Pandas DataFrame. В этом посте мы сосредоточимся на реализации Polars на Python, но имейте в виду, что она также написана для работы с набирающим популярность языком Rust.

Прежде чем продолжить, позвольте мне быть первым, кто расскажет о моем осторожном оптимизме в отношении любого нового программного обеспечения, подобного этому. Всегда есть большой вопрос: «Станет ли это мейнстримом?» К сожалению, я слишком много раз видел, как действительно крутая программа вначале вызывала много шума, а потом исчезала. Что касается Polars, я думаю, что еще слишком рано принимать такое решение в долгосрочной перспективе, но я дам оценку своим личным мыслям о Polars в конце этого поста.

Это вводное руководство специально написано для людей, которые уже знакомы с библиотекой Pandas, и я буду проводить прямое сравнение/сопоставление синтаксиса и производительности Polars и Pandas. Если вы хотите следовать более плавно, пожалуйста, найдите мой код здесь, на GitHub. В демонстрационных целях мы будем использовать классический набор данных Титаника. Кроме того, для контекста показателей производительности, которые я покажу, я выполняю всю эту работу на стандартном MacBook Pro 2021 года с чипом M1 Pro. (Я также проверил это на Microsoft Surface Pro 9 под управлением Windows 11 и могу подтвердить, что там все работало аналогично.)

Последнее замечание перед тем, как перейти к основной части этого поста: Polars все еще находится ОЧЕНЬ рано в своем жизненном цикле, поэтому не удивляйтесь, если даже через 6 месяцев содержимое этого поста устарело.

Хорошо, давайте приступим к изучению Полярных кругов! 🐻‍❄️

Монтаж

К счастью, установить Polars очень просто. Вы можете установить Polars так же, как и любую другую библиотеку Python. Вот конкретная команда, которую вы можете использовать для установки Polars из PyPI.

pip install polars

Время от времени в этом руководстве нам придется делать некоторые переводы между Pandas и Polars. (Да, это не идеально, и я бы предпочел этого избежать, но на данный момент это единственный способ обойти некоторые проблемы, с которыми я столкнулся.) Для этого вам также потребуется установить библиотеку PyArrow Python. . Подобно установке Polars, мы можем запустить следующую команду, чтобы установить PyArrow из PyPI.

pip install pyarrow

Этот последний шаг установки является необязательным, но может оказаться полезным для будущей работы. Как упоминалось во введении, я намерен продемонстрировать производительность Pandas по сравнению с Polars, и, выполняя эту работу в блокноте Jupyter, мы могли бы запустить магическую команду Jupyter %% time для вывода времени выполнения каждой конкретной ячейки. Это, естественно, может стать очень утомительным для ввода, и, к счастью, мы можем установить специальное расширение Jupyter, которое будет автоматически отображать время выполнения каждой ячейки в крошечной строке текста под каждой ячейкой выполнения. Для этого нам нужно запустить следующие 3 команды в вашем CLI.

pip install jupyter_contrib_nbextensions
jupyter contrib nbextension install --user
jupyter nbextension enable execute_time/ExecuteTime

Приведенные выше команды включают новый переключатель в пользовательском интерфейсе Jupyter, который будет правильно отображать время выполнения для каждого запуска ячейки. Чтобы включить это в интерфейсе блокнота Jupyter, перейдите к Cell > Execution Timings и выберите Toggle Visibility (all). Скриншот ниже также демонстрирует это соответствующим образом.

Начиная

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

Импорт панд и поляр

Конечно, первое, что нам нужно сделать, это соответствующим образом импортировать каждую из соответствующих библиотек Python. Как известно пользователям Pandas, при импорте Pandas почти получает псевдоним pd. Точно так же Polars также часто называют двумя буквами pl.

# Importing Pandas and Polars
import pandas as pd
import polars as pl

Загрузка данных из файла CSV

В этом посте вы обнаружите, что у Polars и Pandas иногда могут быть очень разные способы ведения дел, а в других случаях синтаксис будет точно таким же. К счастью, этот первый экземпляр абсолютно одинаков от Pandas до Polars. Вот код, демонстрирующий это сходство.

# Setting the filepath where I have saved the Titanic dataset locally
TITANIC_FILEPATH = '../data/titanic/train.csv'

# Loading the Titanic dataset with Pandas
df_pandas = pd.read_csv(TITANIC_FILEPATH)

# Loading the Titanic dataset with Polars
df_polars = pl.read_csv(TITANIC_FILEPATH)

Прежде чем двигаться дальше, давайте поговорим о производительности этих библиотек. Как вы можете видеть на снимке экрана ниже, загрузка Polars была на 1 миллисекунду быстрее, чем загрузка Pandas. Понятно, что каждый раз, когда я запускал эти ячейки, я получал разные результаты, но я могу сказать, что Polars всегда был быстрее. Это будет повторяющаяся тема на протяжении всего поста.

Просмотр первых строк каждого кадра данных

Сразу после загрузки CSV первое, что мне нравится делать, — это просматривать первые несколько строк DataFrame, просто чтобы понять, с чем я работаю. С точки зрения синтаксиса, пользователи Pandas сразу освоятся с реализацией Polars, поскольку она точно такая же.

# Viewing the first few rows of the Pandas DataFrame
df_pandas.head()

# Viewing the first few rows of the Polars DataFrame
df_polars.head()

Хотя синтаксис один и тот же, вывод Pandas и Polars интересно отличается, и по большей части мне действительно очень нравится, как Polars отображает вывод здесь. Как вы можете видеть ниже, Polars отображает тип данных каждой соответствующей функции непосредственно под названием каждой функции. Более того, синтаксис строковых столбцов показывает значения, заключенные в двойные кавычки. Лично мне это очень нравится, потому что Pandas не совсем четко определяет типы данных каждого столбца, особенно когда речь идет о строках. Единственная странная особенность Polars заключается в том, что он не отображает значения индекса каждой строки слева, как это делает Pandas. Чтобы было ясно, значения индекса остаются нетронутыми; они просто не отображаются в этом представлении. (Также обратите внимание, что в этом случае поляки бегали в два раза быстрее, чем панды.)

Просмотр информации о DataFrame

До сих пор синтаксис обеих библиотек был одинаковым, но теперь мы подошли к моменту, когда они начинают радикально различаться по функциональности. Пользователи Pandas будут знакомы с двумя функциями, каждая из которых отображает соответствующую информацию о DataFrame: info() и describe(). info() показывает такие вещи, как имена функций, типы данных и нулевые значения, а describe() показывает общую статистику, связанную с каждой функцией, такую ​​как среднее значение и стандартное отклонение. Вот код Pandas и скриншот вывода каждой соответствующей функции.

# Viewing the general contents of the Pandas DataFrame
df_pandas.info()

# Viewing stats about the Pandas DataFrame
df_pandas.describe()

В этом отношении Polars сильно отличается от Pandas. Во-первых, нет команды info(). Вместо этого он принимает команду describe() и более или менее объединяет выходные данные, которые мы привыкли видеть в функциях info() и describe() Pandas, в один вывод. Ниже показано, как это выглядит.

# Viewing information about the Polars DataFrame
df_polars.describe()

Честно говоря, я не знаю, как я отношусь к этой реализации. С одной стороны, я думаю, что вывод Polars проясняет, сколько существует нулей, поскольку вам нужно немного посчитать в уме, чтобы понять, сколько нулей есть в выводе Pandas. Но, с другой стороны, Polars теряет информацию, предоставленную Pandas, например, значения межквартильного диапазона. Также обратите внимание, что в выводе Pandas describe() он по праву исключает столбцы на основе строк, тогда как Polars оставляет их там. Обычно мне все равно, но если вы посмотрите, например, на значения «минимум» и «максимум» для функции «Секс», это дает некоторые… ну… неприятные результаты!

Отображение счетчиков значений конкретной функции

Еще одна вещь, которую мне нравится делать, когда я впервые начинаю работать с набором данных с использованием категориальных данных, — это смотреть на количество значений, связанных с каждой категориальной функцией. К счастью, мы вернулись к похожему синтаксису, с которым пользователи Pandas будут знакомы, за исключением того, что вы заметите, что вывод немного отличается.

# Viewing the values associated to the "Embarked" column in the Pandas DataFrame
df_pandas['Embarked'].value_counts()

# Viewing the values associated to the "Embarked" column in the Polars DataFrame
df_polars['Embarked'].value_counts()

Как вы можете видеть, вывод Polars на самом деле немного более информативен, потому что он включает количество нулевых значений, тогда как вывод Pandas вообще не говорит о нулевых значениях. Это тот случай, когда я должен отдать Polars чистую победу. Это действительно удобно!

Обработка данных

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

Получение фрагмента DataFrame

Помните, как я упомянул, что странно, что Polars не показывает значения индекса для каждой строки в выводе head(), но они все еще там? Мы можем доказать это здесь, продемонстрировав, как получить фрагмент каждого DataFrame. К счастью, синтаксис и вывод для Polars и Pandas здесь точно такие же. Кроме того, быстро проверив наши показатели производительности, обратите внимание, как Polars выполнял этот разрез в два раза быстрее, чем Pandas.

# Getting a slice of the Pandas DataFrame using index values
df_pandas[15:30]

# Getting a slice of the Polars DataFrame using index values
df_polars[15:30]

Фильтрация DataFrame по значениям функций

Из всего, что мы продемонстрируем в этом посте, это область, в которой мы можем выполнять аналогичные функции разными способами. Я не буду пытаться продемонстрировать их все, поэтому я выбрал следующий способ, чтобы показать, что Polars может эмулировать функции, аналогичные Pandas, но с немного другим синтаксисом. Ниже приведен код для извлечения всех строк, представляющих подростков на Титанике. (Вывод немного длинный, так как есть 95 подростков, поэтому я не буду показывать вывод. Просто знайте, что вывод действительно такой же.)

# Extracting teenagers from the Pandas DataFrame
df_pandas[df_pandas['Age'].between(13, 19)]

# Extracting teenagers from the Polars DataFrame
df_polars.filter(df_polars['Age'].is_between(13, 19))

Опять же, есть несколько разных способов добиться одинаковых результатов в Pandas и Polars с разным синтаксисом. Единственное, что я хочу подчеркнуть, это то, что официальная документация Polars демонстрирует то, что я сделал выше, используя то, что я считаю странным выбором синтаксиса. Там, где я использую df_polars['Age'] для ссылки на столбец Возраст в фрейме данных Polars, официальная документация вместо этого рекомендует использовать этот синтаксис: pl.col('Age'). Вывод точно такой же, так что это не значит, что что-то не так. Вы могли бы подумать, что Polars захочет продемонстрировать вещи как можно ближе к Pandas, поскольку большинство людей, использующих Polars, будут пользователями Pandas, и, как я успешно продемонстрировал, выбор класса df_polars['Age'] работал очень хорошо. На самом деле это довольно часто встречается в документации Polars, поэтому имейте в виду, что, хотя в документации может быть сказано одно, вы можете обойтись более классическим синтаксисом, к которому вы уже привыкли.

Заполнение нулевых значений

До сих пор наш опыт работы с Polars варьировался от нейтрального до положительного. С этой конкретной частью функциональности мы, к сожалению, начинаем отклоняться на какую-то негативную территорию. Заполнить столбец нулевыми значениями в Pandas относительно просто, и мы даже можем применить это заполнение непосредственно на месте с помощью параметра inplace.

# Filling "Embarked" nulls in the Pandas DataFrame
df_pandas['Embarked'].fillna('S', inplace = True)

К сожалению, Polars здесь немного странный. Во-первых, нет эквивалента параметра inplace, и на самом деле это повторяющаяся тема в Polars, как мы снова увидим позже в этом посте. Более того, у Polars на самом деле есть две разные функции для заполнения нулевых значений: fill_null() и fill_nan(). Глядя на документацию по каждому из них, я, честно говоря, не могу сказать вам, почему вы предпочли бы один из них другому. (Конечно, это вполне может быть результатом моего собственного невежества.) В приведенном ниже блоке кода я использую функцию fill_null() для того же эффекта, что и fillna() в Pandas.

# Filling "Embarked" nulls in the Polars DataFrame
df_polars = df_polars.with_columns(df_polars['Embarked'].fill_null('S'))

Группировка данных по именам функций

Чтобы получить более глубокое понимание данных, специалисты по работе с данными очень часто группируют данные вместе, чтобы понять, как группы данных могут делиться с нами новыми идеями. В этом отношении пользователи Pandas будут хорошо знакомы с функцией groupby(). К сожалению, у Polars также есть функция groupby(), но ее вывод сильно отличается. Пользователи Pandas сочтут эту разницу неприятной, и я явно не смог найти способ эмулировать вывод Pandas, используя другой синтаксис Polars. (Конечно, я, по общему признанию, не очень старался. 😅) Посмотрите ниже, как один и тот же синтаксис дает очень разные результаты в каждой библиотеке.

# Grouping data by ticket class and gender to view counts in the Pandas DataFrame
df_pandas.groupby(by = ['Pclass', 'Sex']).count()

# Grouping data by ticket class and gender to view counts in the Polars dataframe
df_polars.groupby(by = ['Pclass', 'Sex']).count()

Разработка функций

Хотя разработка функций, безусловно, может считаться типом обработки данных, я решил выделить это в отдельный соответствующий раздел, поскольку он связан с другой работой, которую я делал в прошлом. В рамках этой записной книжки на GitHub я продемонстрировал, как можно выполнять проектирование признаков в наборе данных Titanic. В этом разделе мы не будем описывать каждую часть разработки функций, но мы продемонстрируем несколько вещей, чтобы вы могли понять, как эта же работа сравнивается в Pandas и Polars. Мы начнем заново, перезагрузив каждый DataFrame с нуля с помощью этого кода.

# Reloading each DataFrame from scratch
df_pandas = pd.read_csv(TITANIC_FILEPATH)
df_polars = pl.read_csv(TITANIC_FILEPATH)

Удаление ненужных функций

Почти в каждом наборе данных, с которым вы будете работать, вы найдете функции, которые не имеют отношения к делу и должны быть удалены перед передачей в любой алгоритм машинного обучения. Хотя это несложно сделать в Polars, помните, что функции Polars не имеют аналогичного параметра inplace, который позволил бы нам обновлять фрейм данных Polars на месте. Вот синтаксис для удаления функций в обеих библиотеках.

# Dropping unnecessary features from the Pandas DataFrame
df_pandas.drop(columns = ['PassengerId', 'Name', 'Ticket', 'Cabin'], inplace = True)

# Dropping unnecessary features from the Polars DataFrame
df_polars = df_polars.drop(columns = ['PassengerId', 'Name', 'Ticket', 'Cabin'])

Категориальные функции горячего кодирования

Помните в начале, когда я упомянул, что нам нужно будет установить PyArrow, чтобы преобразовать наш DataFrame Polars в Pandas DataFrame? Что ж, вот наш первый пример того, почему мы должны это сделать. Я лично предпочитаю использовать реализация горячего кодирования в кодировщике категорий для моей работы с горячим кодированием. Для контекста, вот как вы можете импортировать это после установки.

# Importing the one-hot encoding object from Category Encoders
from category_encoders.one_hot import OneHotEncoder

Если бы мы выполнили однократное кодирование для функции «Пол» (он же пол) с помощью Pandas, вот как выглядел бы синтаксис.

# Instantiating One Hot Encoder objects for the Pandas DataFrame
sex_ohe_encoder_pandas = OneHotEncoder(use_cat_names = True, handle_unknown = 'ignore')

# Performing a one hot encoding on the "Sex" column for the Pandas DataFrame
sex_dummies_pandas = sex_ohe_encoder_pandas.fit_transform(X_pandas['Sex'])

# Concatenating the gender dummies back to the original Pandas DataFrame
X_pandas = pd.concat([X_pandas, sex_dummies_pandas], axis = 1)

# Dropping the original "Sex" column in the Pandas DataFrame
X_pandas.drop(columns = ['Sex'], inplace = True)

К сожалению, кодировщик категорий OneHotEncoder не настроен для работы с Polars. Если бы мы выполнили следующую строку как есть, мы бы увидели ошибку на скриншоте под ней.

# Performing a one hot encoding on the "Sex" column for the Polars DataFrame
sex_dummies_polars = sex_ohe_encoder_polars.fit_transform(X_polars['Sex'])

Для этого есть обходной путь, но, к сожалению, это не первый раз, когда мы сталкиваемся с такой серьезной проблемой. Ниже приведен полный обходной путь использования Polars для выполнения одноразового кодирования. Обратите внимание, что перед подгонкой фрейма данных Polars к объекту OneHotEncoder нам сначала нужно будет преобразовать его в фрейм данных Pandas. Затем, после преобразования, мы можем просто преобразовать его обратно в Polars DataFrame.

# Instantiating One Hot Encoder objects for the Polars DataFrame
sex_ohe_encoder_polars = OneHotEncoder(use_cat_names = True, handle_unknown = 'ignore')

# Performing a one hot encoding on the "Sex" column for the Polars DataFrame
sex_dummies_polars = sex_ohe_encoder_polars.fit_transform(X_polars['Sex'].to_pandas())

# Converting the Polars dummies from a Pandas DataFrame to a Polars DataFrame
sex_dummies_polars = pl.from_pandas(sex_dummies_polars)

# Concatenating the gender dummies back to the original Polars DataFrame
X_polars = pl.concat([X_polars, sex_dummies_polars], how = 'horizontal')

# Dropping the original "Sex" column in the Polars DataFrame
X_polars = X_polars.drop(columns = ['Sex'])

Наконец, обратите внимание, что реализация функции concat() в Polars немного отличается от Pandas. Там, где Pandas использует параметр axis, чтобы указать, как выполнить конкатенацию, Polars вместо этого использует how и строковые значения. Я лично предпочитаю, как Polars реализовал это здесь.

Биннинг числовых данных

Способ, который я выбрал для разработки функции «Возраст», заключался в том, чтобы распределить ее по соответствующим возрастным группам. Например, люди в возрасте от 13 до 19 лет будут классифицироваться как подростки, тогда как все лица старше 60 лет будут считаться пожилыми. У Pandas есть очень хорошая функция под названием cut(), которая выполняет это объединение в соответствии с входными данными, которые вы ей предоставляете. Вот синтаксис для этого.

# Establishing our bins values and names
bin_labels = ['child', 'teen', 'young_adult', 'adult', 'elder']
bin_values = [-1, 12, 19, 30, 60, 100]

# Applying "Age" binning for the Pandas DataFrame
age_bins_pandas = pd.DataFrame(pd.cut(X_pandas['Age'], bins = bin_values, labels = bin_labels))

Polars предлагает собственную реализацию cut(), но ее вывод радикально отличается от Pandas до такой степени, что лично я считаю ее непригодной для использования. Вот синтаксис и вывод этого кода.

# Applying "Age" binning for the Polars DataFrame
age_bins_polars = pl.cut(X_polars['Age'], bins = bin_values)
age_bins_polars.head()

Глядя на вывод, действительно кажется, что биннинг сработал, но он сделал несколько странных вещей. Во-первых, он не будет принимать мои семантические имена, установленные массивом bin_labels. Во-вторых, не сохранялся порядок строк при их передаче в функцию. Вместо этого вы можете видеть, что выходные данные Polars теперь отсортированы по значениям в порядке возрастания, начиная с самого низкого значения (т. е. самого младшего возраста). Я уверен, что смогу найти обходной путь для первой проблемы, но вторая проблема делает этот вывод бесполезным для меня. Было бы искушение сопоставить возраст с исходным DataFrame, но, как вы можете видеть в этом простом выводе, строки 4 и 5 имеют одинаковое значение 0.75. Хотя это может быть хорошо в этом конкретном случае использования, такая практика может быть опасной для другого набора данных.

(Примечание. Когда я писал этот пост, я обновил Polars 0.16.8 до 0.16.10, в котором функция Polars cut() теперь устарела в пользу использования реализации Polars Series cut(). Не похоже, что это новая реализация устраняет проблему, и на момент публикации этой публикации была отмечена проблема GitHub с запросом на добавление сохранения индекса строки. В общем, это хорошее напоминание о том, что Polars находится в раннем состоянии!)

Прогнозное моделирование с машинным обучением

Этот последний раздел будет кратким, потому что, к сожалению, именно здесь Polars в конечном итоге терпит неудачу для меня, по крайней мере, на момент публикации этого поста. Подобно тому, как я создал блокнот Jupyter для разработки функций в предыдущем проекте Титаник, я попытаюсь подражать тем же шагам, которые я выполнил в моем оригинальном блокноте для прогнозного моделирования Титаника.

Выполнение сплита Train-Test

Отличительной чертой любой хорошей практики машинного обучения, приведенный ниже код демонстрирует, как выполнить разделение обучения и проверки (или проверки обучения), чтобы установить задержку для последующего использования для проверки модели. Поскольку мы будем использовать функцию train_test_split Scikit-Learn, здесь особо нечего замечать, поскольку синтаксис одинаков как для Pandas, так и для фреймов данных Polars. Полагаю, я просто хотел подчеркнуть, что сегодня это работает с Polars из коробки без каких-либо специальных обходных путей. 😃

# Importing Scikit-Learn's train_test_split function
from sklearn.model_selection import train_test_split

# Performing a train-validation split on the Pandas data
X_train_pandas, X_val_pandas, y_train_pandas, y_val_pandas = train_test_split(X_pandas, y_pandas, test_size = 0.2, random_state = 42)

# Performing a train-validation split on the Polars data
X_train_polars, X_val_polars, y_train_polars, y_val_polars = train_test_split(X_polars, y_polars, test_size = 0.2, random_state = 42)

Выполнение прогнозного моделирования

Мы, наконец, подошли к моменту, когда Polars, к сожалению, падает с рельсов. В приведенном ниже коде я демонстрирую, как вы можете подогнать фреймы данных Pandas к классификатору случайных лесов Scikit-Learn, который должен давать выходные данные в этом красивом синем поле.

# Instantiating a Random Forest Classifier object for the Pandas DataFrame
rfc_model_pandas = RandomForestClassifier(n_estimators = 50,
                                          max_depth = 20,
                                          min_samples_split = 10,
                                          min_samples_leaf = 2)

# Fitting the Pandas DataFrame to the Random Forest Classifier algorithm
rfc_model_pandas.fit(X_train_pandas, y_train_pandas.values.ravel())

К сожалению, я наткнулся на кирпичную стену, пытаясь сделать то же самое с Polars DataFrame. Когда я пытаюсь запустить приведенный ниже блок кода, я получаю сообщение об ошибке, которое вы видите на скриншоте ниже.

# Instantiating a Random Forest Classifier object for the Polars DataFrame
rfc_model_polars = RandomForestClassifier(n_estimators = 50,
                                          max_depth = 20,
                                          min_samples_split = 10,
                                          min_samples_leaf = 2)

# Fitting the Polars DataFrame to the Random Forest Classifier algorithm
rfc_model_polars.fit(X_train_polars, y_train_polars.values.ravel())

Я провел целый час, просматривая исходный код Scikit-Learn, чтобы понять, что здесь происходит, и до сих пор не совсем понимаю, почему он не считывает формы данных Polars DataFrame так же, как данные Pandas DataFrames. При запуске таких команд, как df_polars.shape и других подобных, он постоянно отображает тот же вывод, что и соответствующие команды Pandas. Это определенно была головная боль.

Теперь понятно, что Scikit-Learn была единственной алгоритмической библиотекой, которую я пробовал для этого эксперимента. Вы можете получить другие результаты с другими алгоритмическими библиотеками, такими как XGBoost или LightGBM, но я искренне склонен полагать, что у большинства — если не у всех — будет та же проблема, что и у Scikit-Learn. (Это, по общему признанию, наивное предположение, поэтому проверьте мою работу, пожалуйста! 😂)

Заключительные мысли

В общем, то, что я увидел с Polars, мне очень понравилось. Мы постоянно видели более высокую производительность от Polars, и хотя это был относительно тривиальный вариант использования, я могу представить, что этот прирост производительности можно значительно оценить в масштабе. Мне также очень понравились другие вещи, например, как они отображают типы данных каждой функции при отображении данных с помощью такой функции, как head(). Такие мелочи ценятся такими людьми, как я, гораздо больше, чем можно было бы ожидать.

К сожалению, я не могу рекомендовать Polars в его нынешнем состоянии для производственного сценария машинного обучения «в прайм-тайм». (Напоминание: самая последняя версия на момент публикации — 0.16.10). Сбои, которые я наблюдал с функцией cut(), и невозможность интеграции с кодировщиками категорий или классификатором случайного леса Scikit-Learn, к сожалению, стали для меня препятствием. Я предполагаю, что это препятствие существует со многими другими библиотеками, привыкшими к Pandas сегодня.

Если бы я был более чистым аналитиком данных, не занимающимся машинным обучением, возможно, Polars мог бы пройти в этом конкретном контексте. Похоже, что больше всего проблем у Polars на данный момент возникает, когда он пытается интегрироваться с другими библиотеками. (Что, конечно же, не вина Polars!) Я вижу, где аналитик данных может использовать Polars и ничего больше, и в этом случае будьте осторожны и действуйте. (Будьте осторожны, чтобы не получить cut()! 😂)

В конце концов, я просто ценю то, как хорошие люди стараются сделать то, что уже было хорошо, еще лучше. Когда впервые были представлены Numpy и Pandas, прирост производительности по сравнению с ванильным Python был ошеломляющим, настолько, что казалось, что лучше и быть не может. А потом приходит Polars и демонстрирует нам, что мы можем работать еще лучше. Это просто потрясающе. Спасибо, команда Polars, за вашу усердную работу, и я с нетерпением жду возможности увидеть, как Polars развивается! 🐻‍❄️