はじめに
セルフ夏期講習の3日目として、データサイエンス100本ノック(構造化データ加工編)をPolarsで解く作業を再開した。
8月9日はP-036まで進めた。今回はP-037以降に取り組み、P-052まで回答を記入した。まだ全100問の途中だが、結合、クロス集計、日付処理など、実務でも使う機会の多そうな操作が続き、学んだ内容を一度整理したくなったため記録する。
今回の進捗
- データの結合(P-037〜P-040)
- 前回値との差分と複数行前の値(P-041〜P-042)
- 年代・性別によるクロス集計と縦横変換(P-043〜P-044)
- 文字列・日付・エポック秒の変換(P-045〜P-051)
- 売上金額による二値化(P-052)
- P-053〜P-100
今回学んだこと
結合方法を結果の形から考える
内部結合、外部結合、直積を続けて扱ったことで、結合方法を単なるオプション名ではなく「どの行を残したいか」で考えられるようになった。
P-040の直積では、結合キーを使わず、すべての店舗とすべての商品を組み合わせる。
df_store_product = df_store.join(
df_product,
how="cross",
)
通常の結合がキーの一致を基準に行を残すのに対し、直積は左の行数と右の行数を掛けた数だけ組み合わせを作る。この違いを具体的な表としてイメージできた。
shift()とdiff()の違い
日ごとの売上を集計した後、前回の値を参照するにはshift()、前回との差を求めるにはdiff()を使う。
df_daily.with_columns(
pl.col("amount_sum").shift(1).alias("previous_amount_sum"),
pl.col("amount_sum").diff().alias("amount_sum_diff"),
)
shift(1)は値を1行ずらして表示し、diff()は現在値から1行前の値を引く。どちらも「前の行」を基準にするため、先に日付順へ並べる必要があることも重要だった。
横持ちと縦持ちを変換する
P-043では年代を縦、性別を横に並べるためにpivot()を使った。P-044では、その結果をunpivot()で縦持ちに戻した。
横持ち:age_group | male | female | unknown
縦持ち:age_group | gender_cd | amount
同じデータでも、集計表として見せたい場合と、後続処理で扱いやすい形にしたい場合とでは適切な持ち方が異なる。列名とセルの値のどちらを変換しているのかを意識する必要があった。
型に応じて名前空間を使い分ける
日付処理では、見た目が同じ値でも型によって利用する処理が変わる。
- 文字列型には
.str - 日付・日時型には
.dt - 整数型の日付は、一度文字列または日時へ変換する
例えば、UNIX秒を日付型へ変換する場合は次のように書ける。
pl.from_epoch(
pl.col("sales_epoch"),
time_unit="s",
).dt.date()
また、月を01、02のような0埋め2桁で取り出す場合は、整数ではなく文字列として書式化する。
pl.from_epoch(
pl.col("sales_epoch"),
time_unit="s",
).dt.to_string("%m")
エラーが出たときはメソッドだけでなく、対象列がString、Int64、Date、Datetimeのどれなのかを確認することが解決への近道だった。
感想
今回は、単純な抽出や集計から一歩進み、データの形や型を変換する問題が多かった。特に、横持ちと縦持ち、前行の参照、UNIX秒の扱いは、処理結果を頭の中で表として想像しないとコードを書きにくかった。
一方で、Polarsの式は処理の意図を順番に組み立てやすいと感じた。select()、with_columns()、group_by()、pivot()を「最終的にどの列を並べたいか」から逆算すると、少しずつ書き方が見えるようになってきた。
結局PolarsとPandasのどちらがよい?
比較したい際の利点と欠点を下に示す。
| 手法 | 利点 | 欠点 |
|---|---|---|
| Pandas | ・ナレッジ豊富 ・わかりやすい ・scikit-learnといったツールとの相性◯ |
・読み込みが遅い |
| Polars | ・読み込み早い ・コード法則は難しくはない |
・データサイエンスツールとのナレッジが蓄積されていない ・verによって形式が変わる 。pandasと似ているが完全一致ではない点が逆に学習障壁を起こす。 |
したがって、目的用途や好みという結論になる。
インフォマティクスにおいて使用する場合に関しては、scikit-learnなど導入が早ければ早いほどいい。それは、コーディングへの学習よりも、解析への解釈や考察に欠ける時間を増やしたいためだ。ゆえに、事前に学習や臨機応変なコード改変が必要なPolarsは、あまり使わないことにしようかと思う。
しかし、pl.read_csvの読み込み速度は、pd.read_csvとくらべてとても早いと実感した。本記事を読んでいる方々において、とても膨大な表をPythonで見ていきたい場合においては、PandasよりもPolarsが有効なこともあると伝えておく。
次回
Numpyを学習する。
そのなかでPandasの復習もできればなあと思っている。