Polarsでaxis=1を使ってしまった方へ

# Polarsは列指向 - 行方向の平均を計算する方法

pandasからPolarsに移行してきた方は、関数の引数に`axis`を指定することが一般的で、ついPolarsでも同じようにしてしまいがちです（私もその一人です）。しかし、Polarsは　**列指向（column-oriented）**　のデータフレームライブラリであるため、行方向の計算には少し工夫が必要です。

この記事では、Polarsで行方向に平均を取る方法について、pandasとの違いを交えながら解説します。

## pandasでの行方向の平均の取り方

まずは、pandasで行方向に平均を取る方法を確認しましょう。

```python
import pandas as pd

# サンプルのデータフレームを作成
df = pd.DataFrame({
    'A': [1, 2, 3],
    'B': [4, 5, 6],
    'C': [7, 8, 9]
})

# 行方向に平均を計算し、新しい列として追加
df['row_mean'] = df.mean(axis=1)

print(df)
```

出力結果：

```
   A  B  C  row_mean
0  1  4  7       4.0
1  2  5  8       5.0
2  3  6  9       6.0
```

pandasでは、`df.mean(axis=1)` とすることで、行方向（各行の値）に対して平均を計算しています。

## Polarsでの行方向の平均の取り方

一方、Polarsではどうでしょうか。

### 列指向と行指向

Polarsは列指向の設計となっており、基本的に列に対する操作が中心です。そのため、行方向の計算を行う場合、専用の関数を使用する必要があります。

### `mean_horizontal` 関数を使用する

行方向に計算を行うために、Polarsには `mean_horizontal` や `sum_horizontal` といった「*_horizontal」関数が用意されています。

```python
import polars as pl

# サンプルのデータフレームを作成
df = pl.DataFrame({
    'A': [1, 2, 3],
    'B': [4, 5, 6],
    'C': [7, 8, 9]
})

# 行方向に平均を計算し、新しい列として追加
df = df.with_columns(
    pl.mean_horizontal(pl.all()).alias("row_mean")
)

print(df)
```

出力結果：

```
shape: (3, 4)
┌─────┬─────┬─────┬─────────┐
│ A   ┆ B   ┆ C   ┆ row_mean│
│ --- ┆ --- ┆ --- ┆ ---     │
│ i64 ┆ i64 ┆ i64 ┆ f64     │
╞═════╪═════╪═════╪═════════╡
│ 1   ┆ 4   ┆ 7   ┆ 4.0     │
│ 2   ┆ 5   ┆ 8   ┆ 5.0     │
│ 3   ┆ 6   ┆ 9   ┆ 6.0     │
└─────┴─────┴─────┴─────────┘
```

`pl.mean_horizontal(pl.all())` により、全ての列に対して行ごとの平均を計算し、新しい列 `row_mean` として追加しています。

### 特定の列のみを対象とする場合

特定の列のみを平均したい場合、`pl.all()` の代わりに列を指定します。

```python
# 'A' と 'B' 列のみを平均
df = df.with_columns(
    pl.mean_horizontal(['A', 'B']).alias("mean_AB")
)

print(df)
```

出力結果：

```
shape: (3, 5)
┌─────┬─────┬─────┬─────────┬────────┐
│ A   ┆ B   ┆ C   ┆ row_mean┆ mean_AB│
│ --- ┆ --- ┆ --- ┆ ---     ┆ ---    │
│ i64 ┆ i64 ┆ i64 ┆ f64     ┆ f64    │
╞═════╪═════╪═════╪═════════╪════════╡
│ 1   ┆ 4   ┆ 7   ┆ 4.0     ┆ 2.5    │
│ 2   ┆ 5   ┆ 8   ┆ 5.0     ┆ 3.5    │
│ 3   ┆ 6   ┆ 9   ┆ 6.0     ┆ 4.5    │
└─────┴─────┴─────┴─────────┴────────┘
```

このように、対象の列をリストで指定することで、その列に対してのみ計算を行います。

### 列の型に注意

Polarsはデータの型に厳密です。もし文字列型の列など、数値計算に適さない型の列が含まれている場合、エラーが発生します。そのような場合は、計算に含める列を数値型のみに限定する必要があります。

たとえば、データフレームに文字列型の列がある場合：

```python
df = pl.DataFrame({
    'A': [1, 2, 3],
    'B': [4, 5, 6],
    'C': [7, 8, 9],
    'D': ['x', 'y', 'z']  # 文字列型の列
})

# 全ての列を対象にするとエラーになる
# df = df.with_columns(
#     pl.mean_horizontal(pl.all()).alias("row_mean")
# )

# 数値型の列のみを対象にする
df = df.with_columns(
    pl.mean_horizontal(pl.col(pl.Numeric)).alias("row_mean")
)

print(df)
```

出力結果：

```
shape: (3, 5)
┌─────┬─────┬─────┬─────┬─────────┐
│ A   ┆ B   ┆ C   ┆ D   ┆ row_mean│
│ --- ┆ --- ┆ --- ┆ --- ┆ ---     │
│ i64 ┆ i64 ┆ i64 ┆ str ┆ f64     │
╞═════╪═════╪═════╪═════╪═════════╡
│ 1   ┆ 4   ┆ 7   ┆ x   ┆ 4.0     │
│ 2   ┆ 5   ┆ 8   ┆ y   ┆ 5.0     │
│ 3   ┆ 6   ┆ 9   ┆ z   ┆ 6.0     │
└─────┴─────┴─────┴─────┴─────────┘
```

`pl.col(pl.Numeric)` を使用することで、数値型の列のみを選択しています。

## まとめ

- **Polarsは列指向**のデータフレームライブラリであるため、行方向の計算には専用の関数が必要。
- 行方向の計算を行う場合、`mean_horizontal` や `sum_horizontal` などの「*_horizontal」関数を使用する。
- pandasのように `axis=1` を指定するスタイルはPolarsには存在しない。
- 計算対象の列を明示的に指定することで、必要な計算のみを効率的に行える。
- データ型に注意し、数値型の列のみを計算に含めるようにする。

Polarsの列指向の特性を理解し、適切に行方向の計算を行うことで、より効率的なデータ処理が可能になります。

## 参考情報

- [Polars公式ドキュメント - Horizontal Operations](https://pola-rs.github.io/polars/py-polars/html/reference/expressions/api/polars.mean_horizontal.html)
- [Polarsユーザーガイド](https://pola-rs.github.io/polars-book/)
- [pandas公式ドキュメント - DataFrame.mean](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mean.html)

ぜひ、Polarsでのデータ処理にチャレンジしてみてください！