pandasからpolarsへの移行: 基本的な処理の比較

# はじめに

いくつかの基本的な処理をpandasとpolarsの両方で記述しました。
pandasからpolarsに移行する際の参考になればと思います。

polarsそのものに対する説明やメソッド等の説明は特にしないので、必要であれば他の人の記事や公式ドキュメントを参照することをおすすめします。

https://pola-rs.github.io/polars/py-polars/html/reference/

ライブラリのバージョンは以下の通り
- pandas==1.5.3
- polars==0.16.16

ライブラリは以下のような形で読み込んでいます。
```python
import pandas as pd
import polars as pl
```

# 読み込み・書き込み
## csvの読み込み

**pandas**
```python
df = pd.read_csv("data.csv")
```
**polars**
```python
df = pl.read_csv("data.csv")
```
ほぼ同じ記法で書けます。
キーワード引数を使用する場合は、引数の名称が微妙に異なっているので注意が必要です。
詳細は公式ドキュメントを参照してください。

https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html

https://pola-rs.github.io/polars/py-polars/html/reference/api/polars.read_csv.html#polars-read-csv

## csvの書き込み

**pandas**
```python
df.to_csv("data_2.csv", index=False)
```
**polars**
```python
df.write_csv("data_2.csv")
```
メソッド名が違うだけで基本同じです。
こちらもcsvの読み込みと同じでキーワード引数の名称が微妙に異なっているので注意が必要です。

またpolarsにはindex列が存在しないため、`.write_csv()`時にindexは書き込まれません。
indexが欲しい場合は、`.with_row_count()`でindex列を追加しましょう。

**polars**
```python
df.with_row_count("idx").write_csv("data_2.csv")
```


# 行の操作

## 行の追加

**pandas**
```python
df_2 = pd.DataFrame(
    {
        "A": [0.2, 0.1, 0.3, 0.1, 0.5],
        "B": [0.8, 0.9, 0.6, 0.4, 0.2],
        "C": [0.4, 0.2, 0.7, 0.1, 0.8],
    }
)
df = pd.concat([df, df_2], ignore_index=True)
```
**polars**
```python
df_2 = pl.DataFrame(
    {
        "A": [0.2, 0.1, 0.3, 0.1, 0.5],
        "B": [0.8, 0.9, 0.6, 0.4, 0.2],
        "C": [0.4, 0.2, 0.7, 0.1, 0.8],
    }
)
df = pl.concat([df, df_2])
```
polarsでは`ignore_index`でindexを振りなおす必要はありません。

## 行の選択

**pandas**
```python
df.loc[[0, 2, 4], :]
```
**polars**
```python
df[[0, 2, 4]]
```
polarsには`.loc`や`.iloc`が存在しません。選択する行はそのまま`[]`に入れます。

# 列の操作

## 列の追加

### 既存の列から新たな列を計算する場合

**pandas**
```python
df["A*C"] = df["A"] * df["C"]
```
**polars**
```python
df = df.with_columns((pl.col("A") * pl.col("C")).alias("A*C"))
```
polarsの方は若干ややこしく見えますが、`pl.col()`に列名を入れて式を記述し、`.alias()`に新たな列名を記述すればよいです。
また、式全体を`()`で囲まないと正しい処理がされないので注意してください。
今回の場合は`pl.col("A") * pl.col("C")`を`()`で囲む必要があります。

ちなみにpolarsにおいて、`.alias()`を既存の列と同じ名称にすると、列の値を更新できます。

**polars**
```python
df = df.with_columns((pl.col("A") * pl.col("C")).alias("A"))
```


### DataFrame外のデータを追加する場合

**pandas**
```python
d = [0.2, 0.3, 0.2, 0.1, 0.6]
df["D"] = d
```
**polars**
```python
d = [0.2, 0.3, 0.2, 0.1, 0.6]
df = df.with_columns(pl.Series(d).alias("D"))
```
データ形式が`Series`になっていない場合は、`pl.Series`に入れる必要があるようです。

## 列の削除

**pandas**
```python
df = df.drop(["A", "B"], axis=1)
```
**polars**
```python
df = df.drop(["A", "B"])
# もしくは
df = df.drop("A", "B")
```
polarsの場合は`axis=1`の指定が必要ありません。というより`axis`引数自体が無いようです。

## 列の選択

**pandas**
```python
df[["A", "B"]]
```
**polars**
```python
df.select(["A", "B"])
```
`.select()`を使う必要があるだけで、記法は大体同じです。

# その他

## DataFrameのコピー

**pandas**
```python
df_copy = df.copy()
```
**polars**
```python
df_copy = df.clone()
```
どちらもディープコピーをします。

## numpyへの変換

**pandas**
```python
df_numpy = df.values
# もしくは
df_numpy = df.to_numpy()
```
**polars**
```python
df_numpy = df.to_numpy()
```
polarsでは`.values`は使えません。

# おわりに

本格的にpolarsに移行するには本記事の内容は薄いですが、足がかりにはなると思います。
また、気が向いたら内容をより充実させてみたいと思います。