Введение
Вы когда-нибудь имели дело с набором данных, содержащим более 10 миллионов строк? Слишком большой для разумной загрузки в память, но, возможно, слишком маленький для использования базы данных? Как вы справиться с этим?
В этой статье я хочу обсудить, почему поляры могут быть оптимальным выбором для вашего рабочего процесса анализа данных.
Мой набор инструментов по размеру данных
≤ 1000 строк (Excel)
от 1000 до 10 млн строк (dplyr)
от 10 до 50 млн строк (поляры)
≥ 50 млн строк (postgres или снежинка)
Монтаж
Вся информация в этой статье взята с официального сайта и из моего личного опыта работы с пакетом.
Чтобы установить пакет polars для R, вы можете использовать следующую команду.
install.packages("polars", repos = "https://rpolars.r-universe.dev")
Примечание. Пакета еще нет в CRAN, поэтому его необходимо загрузить из репозитория R-Universe.
Настраивать
Прежде чем мы углубимся в детали использования polars, давайте создадим огромный набор случайных данных и сохраним его как файл паркета.
# Large Example Dataset (2GB of Memory) example_data <- wakefield::r_data_frame( n = 15000000, wakefield::name(replace = TRUE), wakefield::sex_inclusive(), wakefield::marital(), wakefield::dob(), wakefield::education(), wakefield::employment(), wakefield::car(), wakefield::political(), wakefield::sat(), wakefield::income(), wakefield::state() ) # Parquet File (200 MB of Space) rio::export( example_data, "example_data.parquet" ) rm(example_data)
Набор данных содержит 15 миллионов строк и занимает около 2 ГБ ОЗУ в моей среде R. Однако, когда я экспортирую фрейм данных в файл паркета, он занимает всего около 200 МБ места!
Изучение данных
Одна из моих любимых особенностей поляров — это их способность работать с наборами данных без считывания их в память. Функции scan_parquet()
и lazy_csv_reader()
создают LazyFrames, которые позволяют вам взаимодействовать с большими наборами данных на диске.
Чтобы проиллюстрировать, как это работает, давайте представим, что мы ничего не знаем о данных примера, которые мы только что создали, и используем поляры для их изучения. Мы можем начать со сканирования файла паркета и использования средства просмотра RStudio для предварительного просмотра первых 5 строк.
# Scan File example_data <- polars::scan_parquet( "example_data.parquet" ) # Preview example_data$ head(5)$ collect()$ to_data_frame() |> View("Data Preview")
Удачного старта! Этот предварительный просмотр показывает нам первые несколько строк данных, но как мы определяем общее количество строк? Что ж, мы можем сделать это, мгновенно собрав данные в нашу сессию, используя функцию collect()
и запросив атрибут высоты.
# Get Row Count example_data$ collect()$ height #> [1] 1.5e+07
Мы видим, что имеется 1.5e+07
или 15 миллионов строк. Это, конечно, согласуется с нашим предыдущим кодом.
Преобразования данных
Мы также можем использовать поляры для выполнения всевозможных преобразований данных. Например, предположим, что мы хотим разделить столбец «Автомобиль» на два отдельных столбца «Марка» и «Модель».
Вот код, чтобы сделать именно это.
# Split the Cars Column into Make and Model result <- example_data$ with_columns( polars::pl$col("Car")$ cast(polars::pl$dtypes$Utf8)$ str$split(" ")$ arr$first()$ alias("Make"), polars::pl$col("Car")$ cast(polars::pl$dtypes$Utf8)$ str$split(" ")$ arr$last()$ alias("Model") ) # Preview result$ head(5)$ collect()$ to_data_frame()[ c("Car", "Make", "Model") ] #> Car Make Model #> 1 Toyota Corona Toyota Corona #> 2 Hornet Sportabout Hornet Sportabout #> 3 Merc 450SL Merc 450SL #> 4 Lincoln Continental Lincoln Continental #> 5 Merc 240D Merc 240D
Позволь мне объяснить:
- Я использовал
with_columns()
для создания новых столбцов. - Я использовал
polars::pl$col("Car")
, чтобы выбрать столбец Car. - Я использовал
cast(polars::pl$dtypes$Utf8)
, чтобы изменить тип столбца с категориального на строковый, чтобы я мог использовать функцию разделения. - Я использовал
str$split(" ")
, чтобы разделить столбец пробелом на столбец массива списка. - Я использовал
arr$first()
иarr$last()
для получения первого и последнего значения массива соответственно. - Я использовал
alias()
, чтобы переименовать результат.
Имейте в виду, что потребовалось несколько проб и ошибок, чтобы выяснить, как именно преобразовать данные. Обратитесь за помощью к документации.
Скорость
polars работает очень быстро. На сканирование файла паркета и преобразование данных ушло менее 5 секунд. Для сравнения, если я прочитаю файл с помощью rio::import()
и выполню точно такое же преобразование с помощью dplyr, это займет около 5 минут!
# Import the file example_data_big <- rio::import( "example_data.parquet" ) # Transform result <- example_data_big |> dplyr::mutate( Make = stringr::str_split( Car, pattern = " ", simplify = TRUE )[,1], Model = stringr::str_split( Car, pattern = " ", simplify = TRUE )[,2] )
Для гораздо меньших наборов данных я бы предпочел подход dplyr, но в случае больших данных polars меняет правила игры.
Агрегации
Мы также можем выполнить некоторые агрегации данных. Давайте ответим на каждый из следующих бизнес-вопросов:
- Каков средний доход по штату?
- Каков средний балл SAT по политическим взглядам?
- Что считается семейным положением по гендерной идентичности?
Средний доход по штатам
# Mean Income by State example_data$ groupby("State")$ agg( polars::pl$col("Income")$mean() )$ collect()$ to_data_frame() #> State Income #> 1 Oregon 39903.68 #> 2 Connecticut 39981.70 #> 3 Utah 39898.87 #> 4 Idaho 40148.05 #> 5 Michigan 39949.00 #> 6 Wisconsin 39994.35 #> 7 Ohio 40045.60 #> 8 New Jersey 39970.62 #> 9 Washington 39945.20 #> 10 Texas 40057.42 #> ...
Средний балл SAT по политическим взглядам
# Median SAT by Political Alignment example_data$ groupby("Political")$ agg( polars::pl$col("SAT")$median() )$ collect()$ to_data_frame() #> Political SAT #> 1 Democrat 1500 #> 2 Green 1500 #> 3 Libertarian 1501 #> 4 Constitution 1501 #> 5 Republican 1500
Семейное положение по полу
# Marital Status by Gender example_data$ groupby("Sex", "Marital")$ agg( polars::pl$first()$len()$alias("Count") )$ sort("Sex")$ collect()$ to_data_frame() #> Sex Marital Count #> 1 Male Never Married 1001467 #> 2 Male Divorced 999198 #> 3 Male Married 1000448 #> 4 Male Separated 999089 #> 5 Male Widowed 1000569 #> 6 Female Never Married 1002752 #> 7 Female Divorced 998686 #> 8 Female Married 1000996 #> 9 Female Separated 998829 #> 10 Female Widowed 999365 #> ...
Мы видим, что данные равномерно распределены по каждой категории, что напоминает нам, что они полностью фальшивые.
Каждая из этих агрегатных операций, выполняемая с 15 миллионами строк, выполнялась менее чем за секунду.
Заключение
polars — отличный пакет для анализа данных, и я рекомендую вам попробовать его!
Весь код из этой статьи можно найти здесь: polars-in-the-artic (github.com)
Посетите страницу документации для получения дополнительной помощи: Polars R Package (rpolars.github.io)
До следующего!