pola-rs/r-polarsができて
一年経ちました

2023-12-02 Japan.R 2023
@eitsupi

はじめに

自己紹介

  • @eitsupi
  • 最近転職しました
    • 製造業大手 → バイオベンチャー
  • Rを触り初めて4年半
    (Excelに嫌気/R Markdownを使いたかった)
  • Rustを触り初めて1年強
  • Dev Containerが好きで、布教して回っている

前回までのふりかえり

今年初めのTokyo.Rで、polarsパッケージを紹介しました(資料

またこれまでに主にdplyrとの比較という観点で、

arrowを紹介し(資料)、

data.tableを紹介し(資料)、

duckdbも紹介しました(資料)。

今日はdplyrとの比較(速度・構文)ではなく、
「この一年間で何があったか」を簡単にまとめます。

ベンチマークは面倒なので

今回の発表に関連した記事も併せてどうぞ。
https://zenn.dev/eitsupi/articles/r-polars-2023

2023年の進捗

Rust不要の高速インストール

NOT_CRAN="true"とオプトインすることで
Rustソースのビルドをスキップしてインストールできます。

Sys.setenv(NOT_CRAN = "true")
install.packages("polars", repos = "https://rpolars.r-universe.dev")

また、R-universe上では上記のメカニズムで
バイナリRパッケージがビルド済なので、
対応プラットフォームではバイナリインストール可能です。

余談:CRANリリースの可能性? 1/3

今年の7月、これまでグレーゾーンだった
CRAN上のRustソースコードの取り扱いについて明文化されました

https://cran.r-project.org/web/packages/using_rust.html

基本的にはこれに準拠すれば(準拠するために滅茶苦茶頑張れば)
CRANリリースは可能なはずです。

ただし、CRAN上のRustバージョンはPolarsの要求バージョンより
常に数ヶ月~一年古いため、Polarsの開発方針変更がないかぎり
最新バージョンのリリースは不可能かもしれません。

余談:CRANリリースの可能性? 2/3

ちなみに、依存するRustクレートを含めたpolars
ソースコードの容量は30MBを超えるそうです。

通常、Rパッケージのソースコードは5MB未満になるため、
これはかなり大きいです。

これはどのくらい大きいのか?
比較のため、CRAN上のパッケージを容量順に並べてみましょう。

余談:CRANリリースの可能性? 3/3

コード
options(repos = c(CRAN = "https://cran.r-project.org/"))

packages_current <- tools:::CRAN_current_db() # data.frame

lf <- packages_current |>
  tibble::as_tibble(rownames = "package_name") |>
  polars::as_polars_lf()

lf$
  sort("size", descending = TRUE)$
  head(n = 3)$
  select(
    名前 = polars::pl$col("package_name")$str$replace("_.*$", ""),
    `容量 (MB)` = polars::pl$col("size") %/% 10L^6
  ) |>
  knitr::kable()
名前 容量 (MB)
rcdklibs 23
fastrmodels 16
RFlocalfdr.data 14

なんと、30MBを超えるパッケージは現存しません。

もしCRANリリースできたら、CRAN最大のパッケージになります。

きみもpolarsに貢献してCRAN最大のパッケージを実現させよう!

特殊なWebサイト

Rパッケージの公式ドキュメントといえばpkgdownですが、
pkgdownには左サイドバーがなく、表示可能な情報量は少ないです。

大量の独自オブジェクトと
それに紐付いた大量のメソッドのナビゲーションのため
polarsaltdocパッケージを介してMkDocs Materialで
ウェブサイトを構築しています。

Base R API

data.frameを模擬した動作をするように、
Base Rの関数のいくつかのS3メソッドを実装しています。

mtcars_pl <- polars::as_polars_df(mtcars)
mtcars_pl[1:5, c("cyl", "am")]
shape: (5, 2)
┌─────┬─────┐
│ cyl ┆ am  │
│ --- ┆ --- │
│ f64 ┆ f64 │
╞═════╪═════╡
│ 6.0 ┆ 1.0 │
│ 6.0 ┆ 1.0 │
│ 4.0 ┆ 1.0 │
│ 6.0 ┆ 0.0 │
│ 8.0 ┆ 0.0 │
└─────┴─────┘

tidypolars

polarsメンテナの一人でもある@etiennebacherさんが
tidypolarsというパッケージを開発されており、
dplyrの関数をpolarsデータフレーム(とLazyFrame)に使えます。

library(dplyr, warn.conflicts = FALSE)
library(tidypolars, warn.conflicts = FALSE)

polars::as_polars_lf(mtcars) |>
  summarise(across(everything(), .fns = mean), .by = "cyl") |>
  arrange(cyl) |>
  collect()
shape: (3, 11)
┌─────┬───────────┬────────────┬────────────┬───┬──────────┬──────────┬──────────┬──────────┐
│ cyl ┆ mpg       ┆ disp       ┆ hp         ┆ … ┆ vs       ┆ am       ┆ gear     ┆ carb     │
│ --- ┆ ---       ┆ ---        ┆ ---        ┆   ┆ ---      ┆ ---      ┆ ---      ┆ ---      │
│ f64 ┆ f64       ┆ f64        ┆ f64        ┆   ┆ f64      ┆ f64      ┆ f64      ┆ f64      │
╞═════╪═══════════╪════════════╪════════════╪═══╪══════════╪══════════╪══════════╪══════════╡
│ 4.0 ┆ 26.663636 ┆ 105.136364 ┆ 82.636364  ┆ … ┆ 0.909091 ┆ 0.727273 ┆ 4.090909 ┆ 1.545455 │
│ 6.0 ┆ 19.742857 ┆ 183.314286 ┆ 122.285714 ┆ … ┆ 0.571429 ┆ 0.428571 ┆ 3.857143 ┆ 3.428571 │
│ 8.0 ┆ 15.1      ┆ 353.1      ┆ 209.214286 ┆ … ┆ 0.0      ┆ 0.142857 ┆ 3.285714 ┆ 3.5      │
└─────┴───────────┴────────────┴────────────┴───┴──────────┴──────────┴──────────┴──────────┘

まとめ

  • Polarsの勉強になった
  • Rustのビルドの勉強になった
  • CRANポリシーの勉強になった
  • ドキュメントシステムの勉強になった
  • S3の勉強になった
  • S4の勉強になった(polarssql

Enjoy!