ChatGPTでどこまでpolarsに入門できるか
この記事は Polars Advent Calendar 2023 7日目の記事です。
はじめに
今年は ChatGPT の話題で持ち切りの一年でしたね。
複雑なコードも、ChatGPTに教えてもらうとサクッと書けるので、かなり効率よく勉強できるようになりました。
そこで、今日はChatGPTを使って、polars にサクッと入門してみようと思います。
できれば課金をしたくないので、まずは ChatGPT3.5 を使っていきます。
CSVの読み込み
それではまず、CSVの読み込みを教えてもらいましょう。
データは後でJOINなども試したいので、先日開催された素敵な1日コンペ yukiCup 2023 Autumn x atmaCup のデータを使っていきます。
polars で train.csv を読み込むコードを教えて
polars ライブラリを使用して train.csv ファイルを読み込むには、以下のようなコードを
使用します:
import polars as pl
# CSVファイルを読み込む
df = pl.read_csv("train.csv")
# データフレームを表示
print(df)
このコードは、train.csv ファイルを読み込んで polars のデータフレーム df に格納します。
その後、データフレームの内容を表示します。
それでは実行してみましょう。
shape: (6_710, 13)
┌───────────────┬──────┬──────────────┬──────┬───┬──────────────┬──────────┬──────────┬────────────┐
│ 名称 ┆ 棟名 ┆ 種別2 ┆ 国 ┆ … ┆ 管理団体又は ┆ 緯度 ┆ 経度 ┆ is_kokuhou │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ 責任者 ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str ┆ str ┆ ┆ --- ┆ f64 ┆ f64 ┆ i64 │
│ ┆ ┆ ┆ ┆ ┆ str ┆ ┆ ┆ │
╞═══════════════╪══════╪══════════════╪══════╪═══╪══════════════╪══════════╪══════════╪════════════╡
│ 泉布観 ┆ null ┆ 近代/文化施 ┆ null ┆ … ┆ null ┆ 34.69811 ┆ 135.5214 ┆ 0 │
│ ┆ ┆ 設 ┆ ┆ ┆ ┆ ┆ ┆ │
│ 絹本著色准胝 ┆ null ┆ 絵画 ┆ 日本 ┆ … ┆ null ┆ null ┆ null ┆ 0 │
│ 仏母像 ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ │
│ 石上神宮拝殿 ┆ null ┆ 近世以前/寺 ┆ null ┆ … ┆ null ┆ 34.5978 ┆ 135.852 ┆ 1 │
│ ┆ ┆ 院 ┆ ┆ ┆ ┆ ┆ ┆ │
うまくいきました!
幸先のよいスタートです。このまま polars をマスターしていきましょう!
四則演算+列の追加(GPT3.5)
続いて、特徴量を作っていきます。
まずは簡単な四則演算をして列を追加してみましょう。
polarsで「終了」列から「開始」列を減算して、diff列に追加するコードを教えて。
df.with_column(pl.col("終了") - pl.col("開始")).alias("diff")
新たな列の追加には with_column
を使うようです。それでは実行してみましょう。
AttributeError: 'DataFrame' object has no attribute 'with_column'
エラーになってしまいました・・・。with_column
は存在しないようです。
エラーになったことを伝えて、正しいコードを教えてもらいましょう。
AttributeError: 'DataFrame' object has no attribute 'with_column' になりました。
申し訳ありません、polars ライブラリの最新バージョンではwith_column メソッドが
サポートされていないようです。代わりに、新しい列を追加するために with_column
メソッドではなく、with_column 関数を使用する必要があります。以下は修正後のコードです:
(略)
・・・なにやら禅問答のようなことを言ってきました。
特徴量を高速に追加できることがpolarsの旨味ですが、列追加すらできません。
polarsへの入門はできないのでしょうか・・・。
ナレッジカットオフ問題
・・・というわけで、ChatGPTでpolarsに入門しようとすると必ずこの壁にぶつかります。
GPT3.5は、ナレッジカットオフが 2022年1月(2023/12/2時点)なので、polarsのような高速にアップデートされるライブラリの進化に追いつけてないことがあります。
例えば、with_column
は2023年 v0.17.0 で完全廃止され with_columns
に一本化されています。
この問題を理由に、これまで polars への入門を避けていた人も多いのではないでしょうか?
コードの実行速度は圧倒的に polars の方が早いですが、コードを全てChatGPTに書いてもらえばトータルの開発スピードは pandas の方が速い、と判断して polars入門を諦めた人も多いと思います。
ナレッジカットオフの更新
そんななか、先日2023/11/7に開催されたOpenAI DevDayにて、 ナレッジカットオフが2023年4月に更新 される発表がありました。
その際に、「polarsにも答えられる」というツイートもチラホラと見かけました。
(この記事を書くことを決めた理由もこれです)
さあ、課金だ。
検証(GPT4)
ここからテーブルデータを扱う際によく使う13個のタスクを例にGPT4の生成するコードを検証していきます。
polarsのバージョンは 2023年12月7日時点での最新バージョン 0.19.19 を使います。
数が多いので、結論だけを知りたい方は こちら へジャンプ
① 四則演算+列の追加(GPT4)
それでは月額$20の力を見せてもらいましょう。
polarsで「終了」列から「開始」列を減算して、diff列に追加するコードを教えて。
df.with_column((df["終了"] - df["開始"]).alias("diff"))
AttributeError: 'DataFrame' object has no attribute 'with_column'
あれ、だめでした・・・。
AttributeError: 'DataFrame' object has no attribute 'with_column' になりました。
正しいコードを教えてください。
申し訳ありません、Polars の最新の記法で with_column メソッドを使う代わりに、
with_columns メソッドを使用する必要があります。以下は修正されたコードです:
df.with_columns([(df["終了"] - df["開始"]).alias("diff")])
shape: (6_710, 3)
┌──────┬──────┬──────┐
│ 開始 ┆ 終了 ┆ diff │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 │
╞══════╪══════╪══════╡
│ 1868 ┆ 1912 ┆ 44 │
│ 1185 ┆ 1333 ┆ 148 │
│ null ┆ null ┆ null │
│ 1185 ┆ 1333 ┆ 148 │
│ … ┆ … ┆ … │
│ 794 ┆ 1185 ┆ 391 │
│ 1185 ┆ 1333 ┆ 148 │
│ 794 ┆ 1185 ┆ 391 │
│ 1337 ┆ 1392 ┆ 55 │
└──────┴──────┴──────┘
おお!遂に with_columns
にたどり着きました!さすがGPT4です。
この勢いで、どんどん入門していきましょう!
② 表結合(JOIN)
続いて、2つのDataFrame を JOIN してみます。
polarsで、train_dfの`時代`列とera_dfの`時代`列をキーにLEFT JOINする処理を教えて。
train_df.join(era_df, on="時代", how="left")
┌──────┬────────┬──────┬──────┐
│ 国 ┆ 時代 ┆ 開始 ┆ 終了 │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ str ┆ i64 ┆ i64 │
╞══════╪════════╪══════╪══════╡
│ null ┆ 明治 ┆ 1868 ┆ 1912 │
│ 日本 ┆ 鎌倉 ┆ 1185 ┆ 1333 │
│ … ┆ … ┆ … ┆ … │
│ 日本 ┆ 鎌倉 ┆ 1185 ┆ 1333 │
│ 日本 ┆ 平安 ┆ 794 ┆ 1185 │
│ 日本 ┆ 南北朝 ┆ 1337 ┆ 1392 │
└──────┴────────┴──────┴──────┘
問題なく成功しました!
③ 集計特徴量(Group_by)
続いて、集計特徴量の作成 Group_by も試してみましょう。
国毎の開始・終了の最大値を列として追加したい。
df.groupby("国").agg([
pl.col("開始").max().alias("開始_max"),
pl.col("終了").max().alias("終了_max")
])
df.join(grouped_df, on="国", how="left")
DeprecationWarning: `groupby` is deprecated. It has been renamed to `group_by`.
shape: (6_710, 2)
┌──────┬──────────┐
│ 開始 ┆ 開始_max │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞══════╪══════════╡
│ 1868 ┆ 1926 │
│ 1185 ┆ 1926 │
│ … ┆ … │
│ 1185 ┆ 1926 │
│ 794 ┆ 1926 │
│ 1337 ┆ 1926 │
└──────┴──────────┘
これもうまくいきました!いい感じです。
ただ最近、groupby
がgroup_by
になったので、warningがでていますね。
with_column
のように完全に depricated されると、エラーに悩むことになりそうです。
④ 文字列結合
続いて文字列結合です。
`国`列と`時代`列を文字列結合したい。
df.with_column(pl.concat_str(df["国"], df["時代"]).alias("国_時代"))
shape: (6_710, 3)
┌──────┬──────────┬────────────┐
│ 国 ┆ 時代 ┆ 国_時代 │
│ --- ┆ --- ┆ --- │
│ str ┆ str ┆ str │
╞══════╪══════════╪════════════╡
│ null ┆ 明治 ┆ null │
│ 日本 ┆ 鎌倉 ┆ 日本鎌倉 │
│ null ┆ 鎌倉前期 ┆ null │
│ 日本 ┆ 鎌倉 ┆ 日本鎌倉 │
│ … ┆ … ┆ … │
│ 日本 ┆ 平安 ┆ 日本平安 │
│ 日本 ┆ 鎌倉 ┆ 日本鎌倉 │
│ 日本 ┆ 平安 ┆ 日本平安 │
│ 日本 ┆ 南北朝 ┆ 日本南北朝 │
└──────┴──────────┴────────────┘
with_column
は (ry
無事動きました。シンプルに df.with_columns([(pl.col("国") + pl.col("時代")).alias("国_時代")])
でもいい気もしますが色々な記法を知ることは大事です。
⑤ 行抽出(filter)
続いて行抽出(filter)です。
polarsでdfの国列に日本が含む行だけを抽出したい。一致ではなく含むです。
df.filter(df["国"].str.contains("日本"))
shape: (4_030, 2)
┌──────┬────────┐
│ 国 ┆ 時代 │
│ --- ┆ --- │
│ str ┆ str │
╞══════╪════════╡
│ 日本 ┆ 鎌倉 │
│ 日本 ┆ 鎌倉 │
│ 日本 ┆ 鎌倉 │
│ 日本 ┆ 南北朝 │
│ … ┆ … │
│ 日本 ┆ 平安 │
│ 日本 ┆ 鎌倉 │
│ 日本 ┆ 平安 │
│ 日本 ┆ 南北朝 │
└──────┴────────┘
filter
も str.contains
も pandas にはない poalrs 独自の記法ですが、正しく生成されました。いい感じですね。
⑥ 正規表現
続いて正規表現を使ってみましょう。時代 列を見てみると、「古墳時代中期 5世紀」という値がありました。ここから「5」という数値を取得してみます。
polarsを使って、dfの「時代」列から世紀の数値を正規表現を用いて抽出したい。
時代列に含まれる値の例は以下の通り。
・古墳時代中期 5世紀
・(柄)奈良 (頭)室町
・古墳時代前期 3世紀
・宋時代
df.with_columns([
df["時代"].str.extract(r"(\d+)世紀", 1).cast(pl.Int32).alias("世紀")
])
ComputeError: Conversion from `str` to `i32` failed in column '時代' for 2 out of
6710 values: ["5", "3"]
おっと、エラーになってしまいました。
が、問題は正規表現の処理ではなく、その後のcastの部分のようですね。
どうやら一部に全角数字が交じってしまっていることが原因のようです。
以下のエラーになりました。
ComputeError: Conversion from `str` to `i32` failed in column '時代' for 2 out of
6710 values: ["5", "3"]
エラーメッセージから、"5"や"3"のような全角数字が含まれていることが原因で、整数への
変換に失敗していることが分かります。Polarsでは、全角数字を半角数字に変換した後、整数に
変換する必要があります。
以下のコードでは、全角数字を半角数字に変換する処理を追加し、その後で世紀の数値を抽出
しています:
# 全角数字を半角数字に変換する関数
def zenkaku_to_hankaku(s):
return s.translate(str.maketrans('0123456789', '0123456789'))
# `時代`列から全角数字を半角に変換し、世紀の数字を抽出
df.with_columns([
df["時代"].apply(zenkaku_to_hankaku).str.extract(r"(\d+)世紀", 1).cast(pl.Int32)
.alias("世紀")
])
DeprecationWarning: `apply` is deprecated. It has been renamed to `map_elements`.
df["時代"].apply(zenkaku_to_hankaku).str.extract(r"(\d+)世紀", 1).cast(pl.Int32)
.alias("世紀")
shape: (7, 2)
┌──────┬────────┐
│ 世紀 ┆ counts │
│ --- ┆ --- │
│ i32 ┆ u32 │
╞══════╪════════╡
│ 3 ┆ 1 │
│ 5 ┆ 1 │
│ 19 ┆ 4 │
│ 17 ┆ 1 │
│ null ┆ 6698 │
│ 14 ┆ 1 │
│ 16 ┆ 4 │
└──────┴────────┘
無事、全角半角変換も含めて動きました。
こうやって対話形式でエラーを修正できるのはやはり便利ですね。
apply
関数は Deprecated して map_elements
になると warning が出ています。
関数名もどんどん更新されて、アップデートの速さが伺えますね。
⑦ カウントエンコーディング
実践的なテクニックも見ていきましょう。続いてはカウントエンコーディングです。
polarsで「時代」列のカウントエンコーディングを実装したい。
# `時代` 列のカウントエンコーディング
時代_counts = df.groupby("時代").count().rename({"count": "時代_count"})
df.join(時代_counts, on="時代", how="left")
shape: (6_710, 2)
┌──────────┬────────────┐
│ 時代 ┆ 時代_count │
│ --- ┆ --- │
│ str ┆ u32 │
╞══════════╪════════════╡
│ 明治 ┆ 336 │
│ 鎌倉 ┆ 1319 │
│ 鎌倉前期 ┆ 47 │
│ 鎌倉 ┆ 1319 │
│ … ┆ … │
│ 平安 ┆ 1045 │
│ 鎌倉 ┆ 1319 │
│ 平安 ┆ 1045 │
│ 南北朝 ┆ 282 │
└──────────┴────────────┘
一切の修正なく、うまくいきました!
(pythonって変数名に日本語使えるんですね。)
⑧ ラベルエンコーディング
polarsの処理ではないですが、Kaggleでは頻出の処理なので教えてもらいましょう。
`国`列をラベルエンコーディングしたい
# `国` 列をラベルエンコーディング
encoded, labels = df["国"].factorize()
# エンコーディングされた列をデータフレームに追加
df.with_column(encoded.alias("国_encoded"))
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/workspaces/ml-codespaces/polars-advent-calendar/notebook/gpt4.ipynb Cell 6 line 2
1 # `国` 列をラベルエンコーディング
----> 2 encoded, labels = df["国"].factorize()
4 # エンコーディングされた列をデータフレームに追加
5 df.with_column(encoded.alias("国_encoded"))
AttributeError: 'Series' object has no attribute 'factorize'
存在しない関数 factorize
を教えてきました。エラーになったことを伝えてみます。
Polarsでは、factorize メソッドは Series オブジェクトではなく、
select メソッドの一部として使用されます。ラベルエンコーディングを
行うためには、select メソッドと組み合わせて使う必要があります。
以下に修正されたコードを示します。
# `国` 列をラベルエンコーディング
df.with_columns([
df["国"].cast(pl.Categorical).alias("国_encoded")
])
このコードでは、cast メソッドを使用して 国 列をカテゴリカル型に変換し、
それによって自動的にラベルエンコーディングされます。その結果は
国_encoded という新しい列としてデータフレームに追加されます。
なんと!polarsは型変換しただけでラベルエンコーディングされるのでしょうか?
shape: (6_710, 1)
┌────────────┐
│ 国_encoded │
│ --- │
│ cat │
╞════════════╡
│ null │
│ 日本 │
│ null │
│ 日本 │
│ … │
│ 日本 │
│ 日本 │
│ 日本 │
│ 日本 │
└────────────┘
ウソでした・・・。
具体的に sklearn の label_encoder を使うように指示を出してみましょう。
上記ではうまくいきませんでした。sklearnのlabel encoderを使う方法を教えて。
from sklearn.preprocessing import LabelEncoder
# LabelEncoderのインスタンスを作成
encoder = LabelEncoder()
# `国`列をエンコード
encoded_labels = encoder.fit_transform(df["国"].to_numpy())
# エンコードされたデータを新しい列として追加
df.with_column(pl.Series("国_encoded", encoded_labels))
with_column
になってしまうところは、with_columns
に読み替えて実行してみましょう。
shape: (6_710, 2)
┌──────┬────────────┐
│ 国 ┆ 国_encoded │
│ --- ┆ --- │
│ str ┆ i64 │
╞══════╪════════════╡
│ null ┆ 17 │
│ 日本 ┆ 10 │
│ null ┆ 17 │
│ 日本 ┆ 10 │
│ … ┆ … │
│ 日本 ┆ 10 │
│ 日本 ┆ 10 │
│ 日本 ┆ 10 │
│ 日本 ┆ 10 │
└──────┴────────────┘
ちょっとヒントやサポートを与える必要はあるものの、列をラベルエンコーディングし、最後はnumpyからseriesとして追加するところまでいけました!
⑨ max, min, std, sum, mean, median
dfの「開始」列について、max, min, std, sum, mean, median の特徴量を
作って、列として追加したい。
df.with_columns([
df["開始"].max().alias("開始_max"),
df["開始"].min().alias("開始_min"),
df["開始"].std().alias("開始_std"),
df["開始"].sum().alias("開始_sum"),
df["開始"].mean().alias("開始_mean"),
df["開始"].median().alias("開始_median")
])
df["開始"].max().alias("開始_max"),
^^^^^^^^^^^^^^^^^^^^
AttributeError: 'int' object has no attribute 'alias'
with_columns
まではよかったのですが、エラーになってしまいました。
今回はエラーメッセージからエラー原因はわかりにくいですが、模範解答は以下です。
df["開始"]
ではなくpl.col("開始")
と書くべきです。
df.with_columns([
pl.col("開始").max().alias("開始_max"),
pl.col("開始").min().alias("開始_min"),
pl.col("開始").std().alias("開始_std"),
pl.col("開始").sum().alias("開始_sum"),
pl.col("開始").mean().alias("開始_mean"),
pl.col("開始").median().alias("開始_median")
])
shape: (6_710, 6)
┌──────┬──────────┬──────────┬───┬─────────────┬─────────────┐
│ 開始 ┆ 開始_min ┆ 開始_max ┆ … ┆ 開始_mean ┆ 開始_median │
│ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 ┆ ┆ f64 ┆ f64 │
╞══════╪══════════╪══════════╪═══╪═════════════╪═════════════╡
│ 1868 ┆ -14000 ┆ 1926 ┆ … ┆ 1031.611971 ┆ 1185.0 │
│ 1185 ┆ -14000 ┆ 1926 ┆ … ┆ 1031.611971 ┆ 1185.0 │
│ … ┆ … ┆ … ┆ … ┆ … ┆ … │
│ 1185 ┆ -14000 ┆ 1926 ┆ … ┆ 1031.611971 ┆ 1185.0 │
│ 794 ┆ -14000 ┆ 1926 ┆ … ┆ 1031.611971 ┆ 1185.0 │
│ 1337 ┆ -14000 ┆ 1926 ┆ … ┆ 1031.611971 ┆ 1185.0 │
└──────┴──────────┴──────────┴───┴─────────────┴─────────────┘
⑩ Rolling特徴量
続いて、時系列データではないのでこのデータでは不適切な利用ですが、Rolling特徴量の作り方も教えてもらいましょう。
`緯度`列についてrolling特徴量を作りたい。
rolling_mean = df["緯度"].rolling_mean(window_size=3, min_periods=1)
# 結果を新しい列としてデータフレームに追加
df.with_columns(rolling_mean.alias("緯度_rolling_mean"))["緯度_rolling_mean"]
shape: (6_710, 2)
┌──────────┬───────────────────┐
│ 緯度 ┆ 緯度_rolling_mean │
│ --- ┆ --- │
│ f64 ┆ f64 │
╞══════════╪═══════════════════╡
│ 34.69811 ┆ 34.69811 │
│ null ┆ 34.69811 │
│ 34.5978 ┆ 34.647955 │
│ null ┆ 34.5978 │
│ … ┆ … │
│ 35.61229 ┆ 35.053227 │
│ 35.02793 ┆ 35.417503 │
│ null ┆ 35.32011 │
│ null ┆ 35.02793 │
└──────────┴───────────────────┘
⑪ value_counts
続いて、value_counts を見てみましょう。
pandas の value_counts のコードをpolars で実装する方法を教えて。
Polarsでは、Pandasのvalue_counts()関数に直接対応するものはありませんが、同様の結果を
得るためにgroupby()とcount()を組み合わせることができます。例えば、あるデータフレームの
特定の列の値の出現回数をカウントするには、以下のようにします:
(中略)
# 特定の列(例えば 'column_name')の値の出現回数をカウント
value_counts = df.groupby("column_name").count()
shape: (18, 2)
┌────────────────┬───────┐
│ 国 ┆ count │
│ --- ┆ --- │
│ str ┆ u32 │
╞════════════════╪═══════╡
│ 日本 ┆ 4014 │
│ 中国・日本日本 ┆ 1 │
│ 中国・日本 ┆ 9 │
│ ヴェトナム ┆ 2 │
│ … ┆ … │
│ 西洋 ┆ 8 │
│ 朝鮮・日本 ┆ 1 │
│ 中国、日本 ┆ 1 │
│ イギリス ┆ 3 │
└────────────────┴───────┘
polarsにも value_counts
は存在しますが、存在しないことになっていました。
出力としては、group_by("列").count でも問題はないですね。
⑫ ユニーク値の数(n_unique)
特定の列のユニークな値の数を計算するコードする方法を教えてもらいましょう。
polars でdfの`国`列にユニークな値がいくつ入っているかを知りたい。
# '国' 列に含まれるユニークな値の数を計算
unique_countries_count = len(df["国"].unique())
# 結果を表示
print(f"'国' 列に含まれるユニークな値の数: {unique_countries_count}")
'国' 列に含まれるユニークな値の数: 18
成功しました。
間違ってはいないのですが、polars には n_unique
があるので df["国"].n_unique()
の方がシンプルですね。
⑬ Config
最後に、Config設定の変更のやり方を聞いてみましょう。
dfを出力すると行が途中で切れてしまうので、50行表示されるようにしたい。
# 出力設定を変更して50行表示
with pl.ConfigContext(display_max_rows=50):
print(df)
AttributeError: module 'polars' has no attribute 'ConfigContext'
残念ながら、これはだめでした。
ちなみに模範解答は pl.Config.set_tbl_rows(50)
です。
結論
色々とChatGPTに教えてもらいましたが、思ったよりも入門できそうでした。
-
with_column
は間違えがち。 - 基本的な操作については、8割くらいは正しいコードを教えてくれる
- 1割くらいはガイドが必要(例:ラベルエンコーディング)
- 1割くらいは非対応
といった感じでしょうか。
欲を言えば df["列"]
よりも pl.col("列")
を使ったコードを生成してほしかったです。
polarsの力を最大限に引き出すために 遅延評価(Lazy Evaluation) を利用しようと思うと df["列"]
は使えませんからね。
# | 検証 | 結果(GPT4) |
---|---|---|
1 | 列追加 (with_columns) | △(with_columns になりがち) |
2 | 表結合(JOIN) | ◎ |
3 | 集計特徴量(Group_by) | ◎ |
4 | 文字列結合(concat_str) | ◎ |
5 | 行抽出(filter) | ◎ |
6 | 正規表現 | ◎ |
7 | カウントエンコーディング | ◎ |
8 | ラベルエンコーディング | △(sklearnを使って、とガイドが必要) |
9 | max, min, std, sum, mean, median | × |
10 | Rolling特徴量 | ◎ |
11 | value_counts | ○(gropu_by + countで実装。value_countsは知らない) |
12 | n_unique | ○(len + uniqueで実装) |
13 | Config | × |
Polarsのリリース情報
最後に、Polars はいつ時点の情報までを知っているのか調べてみました。
Polarsのリリース情報は以下にまとまっています。
ナレッジカットオフが2023年4月なので、GPT4が把握できているのは Python Polars 0.17.10 あたりまででしょうか。
上の検証からも 0.17.0 での with_column
の廃止にもギリギリ対応という感じでしたね。
その後も、週に1~2回のペースでアップデートされ、Enhancement も Deprecation もまだまだたくさんありそうです。
GPT4のナレッジカットオフが更新された今が入門のチャンスかもしれませんね。
Discussion