技術の木

Pandas×StandardScalerの標準化でNaNにハマったこと

スポンサーリンク

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)する方法や行毎に計算する方法などが考えられたが、今回はシンプルなこの案を採用することにしました

タイトルとURLをコピーしました