Новая библиотека превосходит Pandas по производительности



Книга Новая библиотека превосходит Pandas по производительности

Выпуск pandas датируется 2008 годом, и написана она была на Python, Cython и Си. Сегодня мы сравниваем производительность этой всем известной библиотеки с новой DataFrame библиотекой pypolars, написанной на Rust. Сравнение производится при сортировке и конкатенации данных с 25 миллионами записей, а также при объединении двух CSV-файлов.


Загрузка с форума Reddit данных с именами пользователей


Сначала загрузим с платформы Kaggle CSV-файл, содержащий ~26 миллионов имён пользователей reddit.


И сформируем ещё один CSV-файл с помощью любого текстового редактора или через командную строку:


$ cat >> fake_users.csv
author,n
x,5
z,7
y,6

Сортировка


Теперь сравним алгоритм сортировки двух библиотек:


pandas


import timeit

start = timeit.default_timer()
import pandas as pd

df = pd.read_csv('users.csv')
df.sort_values('n', ascending=False)
stop = timeit.default_timer()

print('Time: ', stop - start)

$ python sort_with_pandas.py
Time: 34.35690135599998

pypolars


import timeit

start = timeit.default_timer()
import pypolars as pl

df = pl.read_csv('users.csv')
df.sort(by_column='n', reverse=True)
stop = timeit.default_timer()

print('Time: ', stop - start)

$ python sort_with_pypolars.py
Time: 23.965840922999973

~24секунды, т. е. pypolars здесь в 1,4 раза быстрее pandas


Конкатенация


А теперь посмотрим, как ведут себя библиотеки при конкатенации двух табличных структур данных и распределении их в одну табличную структуру:


pandas


import timeit

start = timeit.default_timer()
import pandas as pd

df_users = pd.read_csv('users.csv')
df_fake = pd.read_csv('fake_users.csv')
df_users.append(df_fake, ignore_index=True)
stop = timeit.default_timer()

print('Time: ', stop - start)

У pandas это заняло 18 секунд:


$ python concat_with_pandas.py 
Time: 18.12720185799992

pypolars


import timeit

start = timeit.default_timer()
import pypolars as pl

df_users = pl.read_csv('users.csv')
df_fake = pl.read_csv('fake_users.csv')
df_users.vstack(df_fake)
stop = timeit.default_timer()

print('Time: ', stop - start)

Здесь pypolars в 1,2 раза быстрее


$ python concat_with_pypolars.py 
Time: 15.001723207000055

Объединение


Загрузка данных для отслеживания ситуации с COVID


Загрузка данных из проекта по отслеживанию ситуации с COVID с помощью команды даёт в файле all-states-history.csv последние данные о распространении коронавируса по всей территории США:


$ curl -LO https://covidtracking.com/data/download/all-states-history.csv

Загрузка данных по штатам


Это CSV-файл, и в нём каждый штат обозначен соответствующей аббревиатурой. Он нужен для объединения с предыдущим CSV-файлом, в котором приведены лишь аббревиатуры (в столбце state). Данные получим с помощью этой команды:


$ curl -LO https://gist.githubusercontent.com/afomi/8824ddb02a68cf15151a804d4d0dc3b7/raw/5f1cfabf2e65c5661a9ed12af27953ae4032b136/states.csv

Будет выведен файл states.csv с названиями штатов и их сокращёнными обозначениями.


pandas


import timeit

start = timeit.default_timer()
import pandas as pd

df_all_states_history = pd.read_csv('all-states-history.csv')
df_states = pd.read_csv('states.csv')
df_all_states_history.join(df_states.set_index("Abbreviation"), on="state").to_csv("joined_pd.csv")
stop = timeit.default_timer()

print('Time: ', stop - start)

$ python join_with_pandas.py
Time: 0.9691885059996821

$ python join_with_pandas.py 
Time: 0.9691885059996821

Используем csvcut, чтобы провести фильтрацию полученного файла joined_pd.csv:


$ csvcut -c date,state,State joined_pd.csv | head | csvlook 
| date | state | State |
| ---------- | ----- | ----------- |
| 2020-11-16 | AK | ALASKA |
| 2020-11-16 | AL | ALABAMA |
| 2020-11-16 | AR | ARKANSAS |
| 2020-11-16 | AS | |
| 2020-11-16 | AZ | ARIZONA |
| 2020-11-16 | CA | CALIFORNIA |
| 2020-11-16 | CO | COLORADO |
| 2020-11-16 | CT | CONNECTICUT |
| 2020-11-16 | DC | |

Похоже, объединение работает, и это левое объединение. Интересно, почему значения штатов State, обозначаемых аббревиатурами AS и DC, пусты? Потому что этих аббревиатур нет в самом файле states.csv. Если вы посмотрите на аббревиатуры в файле, то не найдете там значений ни AS, ни DC.


Здесь нет аббревиатуры AS:


$ grep AS states.csv 
ALASKA,AK
ARKANSAS,AR
KANSAS,KS
MASSACHUSETTS,MA
NEBRASKA,NE
TEXAS,TX
WASHINGTON,WA

и здесь нет значений для DC:


$ grep DC states.csv

P.S. csvcut находится в csvkit (утилите командной строки, в которой содержатся и некоторые другие полезные инструменты командной строки для очистки, обработки и анализа CSV-файлов).


pypolars


import timeit

start = timeit.default_timer()
import pypolars as pl

df_all_states_history = pl.read_csv('all-states-history.csv')
df_states = pl.read_csv('states.csv')
df_all_states_history.join(df_states, left_on="state", right_on="Abbreviation").to_csv("joined_pl.csv")
stop = timeit.default_timer()

print('Time: ', stop - start)

$ python join_with_pypolars.py
Time: 0.41163978699978543

А теперь посмотрим, как выглядит объединённая табличная структура:


$ csvcut -c date,state,State joined_pl.csv | head | csvlook 
| date | state | State |
| ---------- | ----- | ----------- |
| 2020-11-16 | AK | ALASKA |
| 2020-11-16 | AL | ALABAMA |
| 2020-11-16 | AR | ARKANSAS |
| 2020-11-16 | AZ | ARIZONA |
| 2020-11-16 | CA | CALIFORNIA |
| 2020-11-16 | CO | COLORADO |
| 2020-11-16 | CT | CONNECTICUT |
| 2020-11-16 | DE | DELAWARE |
| 2020-11-16 | FL | FLORIDA |

Похоже, pypolars удалось избежать пустых значений в объединённом столбце. Ведь здесь объединение по умолчанию  —  это внутреннее объединение. В отличие от объединения по умолчанию в pandas, которое является левым объединением. Чтобы получить тот же результат, как в pandas, нужно изменить строку 8 на:


df_all_states_history.join(df_states, left_on=”state”, right_on=”Abbreviation”, how=”left”).to_csv(“joined_pl.csv”)

На моём компьютере получилось ~317 миллисекунд, т. е. здесь:


pypolars в 3 раза быстрее в левом объединении


Заключение


В итоге мы выявили, насколько высокопроизводительна pypolars в сравнении с pandas. Конечно, pandas  —  более зрелая библиотека (разница около 12 лет), и сообщество всё ещё инвестирует в неё. Но если pypolars будут использовать больше, эта новая библиотека наведёт шороху!


Пара полезных ссылок:



563   0  

Comments

    Ничего не найдено.