📈
Pandas でグループごとに標準化する
公式ドキュメントの Example に書いてありました。なんてこったい...
以下のようなグループを持つテーブルデータに対して、グループごとに標準化(もしくは正規化)するのを Pandas でいい感じにできないか調べたので、そのメモです。
グループ | 値 1 | 値 2 |
---|---|---|
A | 0 | 10 |
A | 20 | 30 |
B | 100 | 200 |
B | 300 | 400 |
結論
Pandas の Groupby と Transform を使えばいい感じにできた!
import pandas as pd
import numpy as np
# 標準化を行う関数の定義
def scale(x):
res = (x - np.mean(x)) / np.std(x, ddof=1)
return res
df_scale = df.groupby("グループ").transform(scale)
実際にやってみた
ランダムに整数を作り、それを A と B の2つのグループに分けて、グループごとに標準化を実行してみた。
import numpy as np
import pandas as pd
np.random.seed(123)
# 標準化を行う関数の定義
def scale(x):
res = (x - np.mean(x)) / np.std(x, ddof=1)
return res
# データの準備
X = np.random.randint(0, 100, 12).reshape(6, 2)
groups = ["A", "A", "A", "B", "B", "B"]
df = pd.DataFrame(X, columns=["値 1", "値 2"])
df.insert(0, "グループ", groups)
# 標準化の実施
df_scale = df.groupby("グループ").transform(scale)
df_scale.insert(0, "グループ", groups)
print("標準化する前")
print(df)
print("標準化した後")
print(df_scale)
実行結果
標準化する前
グループ 値 1 値 2
0 A 66 92
1 A 98 17
2 A 83 57
3 B 86 97
4 B 96 47
5 B 73 32
標準化した後
グループ 値 1 値 2
0 A -1.020169 0.977054
1 A 0.978530 -1.021466
2 A 0.041640 0.044412
3 B 0.086711 1.126315
4 B 0.953821 -0.342791
5 B -1.040532 -0.783523
グループ A の値 1 に対して R で検算してみると、以下のようになり、結果が一致した。
> scale(c(66, 98, 83))
[,1]
[1,] -1.02016938
[2,] 0.97852981
[3,] 0.04163957
attr(,"scaled:center")
[1] 82.33333
attr(,"scaled:scale")
[1] 16.01041
結果の上書き
元のテーブルを標準化した値で上書きするには、
# 元のデータを標準化した値で上書きする場合の例
df.loc[:, df_scale.columns] = df_scale
とすれば OK!!
Discussion