DataFrameの数値カラムを標準化したくて・・・
筆者は仕事柄、データ加工を行うことがよくあるのですが、今回はPythonのpandasライブラリを使い、DataFrame内のデータを標準化した際に少し引っかかってしまった事を忘却録として記載したいと思います。
scikit-learnのStandardScalerを使って標準化
- pandas.DataFrameにロードしたデータをカラム毎に標準化した値に変換する
上記の課題の実現のため、標準化にはscikit-learnのStandardScalerを使うことにし、最初次のようなコードを書いていました。
※サンプルデータとしてsklearnのLinnerrudのデータを使う
import sklearn
import pandas
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_linnerud
#サンプルデータ(Linnerrud)のロード
sample = linnerud = load_linnerud()
df = pandas.DataFrame(sample.data, columns=sample.feature_names)
#実例ではNULLデータを含むファイルをロードした為、
#DataFrameにロード後、NaN行を削除しました
#サンプルのため、偶数行を削除
df = df.query('index %2 == 0')
#StandardScalerの準備
scaler = StandardScaler()
stdCols = ['Chins', 'Situps', 'Jumps']
#標準化した値をDataFrameにセット
df.loc[:,stdCols] = pandas.DataFrame(
scaler.fit_transform(df.loc[:, stdCols]),
columns=df.loc[:, stdCols].columns.values
)
#結果を表示
display(df)
結果は、次のようになってしまいました。
NaNがセットされるだけでなく、値も間違っています。
Chins Situps Jumps
0 -1.316322 0.373625 0.115395
2 0.468521 0.249673 0.040947
4 0.914732 1.046503 -0.629088
6 0.691627 1.312113 1.790481
8 -1.539427 -1.432523 -1.187450
10 NaN NaN NaN
12 NaN NaN NaN
14 NaN NaN NaN
16 NaN NaN NaN
18 NaN NaN NaN
いろいろ調べたところ、StandardScaler.fit_transform()で変換したデータは配列型で返却されるため、DataFrameに変換する際にindexがリセットされていることがわかりました。
そのため、以下のようにコードを修正し対応することにしました。
import sklearn
import pandas
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_linnerud
#サンプルデータ(Linnerrud)のロード
sample = linnerud = load_linnerud()
df = pandas.DataFrame(sample.data, columns=sample.feature_names)
#実例ではNULLデータを含むファイルをロードした為、
#DataFrameにロード後、NaN行を削除しました
#サンプルのため、偶数行を削除
df = df.query('index %2 == 0')
#StandardScalerの準備
scaler = StandardScaler()
stdCols = ['Chins', 'Situps', 'Jumps']
#標準化した値をDataFrameにセット
#fit_transform()の結果をDataFrameに変換する際にindexを設定
df.loc[:,stdCols] = pandas.DataFrame(
scaler.fit_transform(df.loc[:, stdCols]),
columns=df.loc[:, stdCols].columns.values,
index=df.index.values
)
#結果を表示
display(df)
実行結果は、問題なさそうです。
Chins Situps Jumps
0 -1.316322 0.373625 0.115395
2 0.245416 -0.706522 1.641585
4 0.468521 0.249673 0.040947
6 -0.647006 -0.706522 -0.703536
8 0.914732 1.046503 -0.629088
10 1.360943 -0.370083 -0.703536
12 0.691627 1.312113 1.790481
14 -1.093216 -1.255449 -0.964105
16 -1.539427 -1.432523 -1.187450
18 0.914732 1.489186 0.599309
最後に
上記以外に元データのindexをリセット(reset_index)する方法や行毎に計算する方法などが考えられたが、今回はシンプルなこの案を採用することにしました