Dragon Arrow written by Tatsuya Nakaji, all rights reserved animated-dragon-image-0164

pandas 正規化

updated on 2019-12-03

イメージ

pandas 正規化

実現したいこと


Exelファイルを正規化する。(筆者は多重回帰分析を行う)


正規化のメリット(多重回帰分析)


正規化をすると、値が意味する絶対量を相対量に変換するため、単位が関係なくなり、各因子の係数(偏回帰係数)が、「寄与率」のように比較できる。

また、私の場合、大学生の期末試験のデータを扱ったりしましたが、試験の満点が各学科で違ったりしても、正規化することで他の学科との平等な生徒の比較ができるようになる。


正規化の式


最小値0、最大値1に正規化

Min-Max Normalization。

$$ x'= \frac{ x - min(x) }{ max(x) - min(x) } $$


平均0、分散1に標準化(正規化と表現したりもする)

平均をμ, 標準偏差をσとする

$$x'= \frac{ x -  \mu  }{  \sigma  }$$


標準偏差について

$$s=  \sqrt{  s ^{ 2 }  } =\frac{ 1 }{ n } \sum_{i=1}^N  (x _{ i } -  \mu )^2 \\ { ここで、s ^{ 2 }は分散,\ nはデータの総数,\ x _{ i } は個々の数値,\ \muは平均値を表します。 } $$


環境


python 3.7.3

scikit 0.21.3


実装


最小値0、最大値1に正規化

>>> from sklearn import preprocessing
>>> data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
>>> norm = preprocessing.minmax_scale(data)
>>> norm
array([[0.  , 0.  ],
       [0.25, 0.25],
       [0.5 , 0.5 ],
       [1.  , 1.  ]])
>>> 


その他の手法

sklearn の StandardScalerMinMaxScaler がそれぞれ 標準化正規化 のモジュールです。主に使うメソッドは次の 3 つです。

  • fit
    パラメータ(平均や標準偏差 etc)計算
  • transform
    パラメータをもとにデータ変換
  • fit_transform
    パラメータ計算とデータ変換をまとめて実行


2次元正規分布の乱数を 50 個用意し、標準化、正規化を行う

import matplotlib.pyplot as plt
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
 
# 元データ
np.random.seed(seed=1)
data = np.random.multivariate_normal( [5, 5],  [[5, 0],[0, 2]],  50 )
 
# 標準化
sc = StandardScaler()
data_std = sc.fit_transform(data)
 
# 正規化
ms = MinMaxScaler()
data_norm = ms.fit_transform(data)
 
# プロット
min_x = min(data[:,0])
max_x = max(data[:,0])
 
min_y = min(data[:,1])
max_y = max(data[:,1])
 
plt.figure(figsize=(5, 6))
plt.subplot(2,1,1)
plt.title('標準化')
plt.xlim([-4, 10])
plt.ylim([-4, 10])
plt.scatter(data[:, 0], data[:, 1], c='red', marker='x', s=30, label='スケール前')
plt.scatter(data_std[:, 0], data_std[:, 1], c='blue', marker='x', s=30, label='標準化 ')
plt.legend(loc='upper left')
plt.hlines(0,xmin=-4, xmax=10, colors='#888888', linestyles='dotted')
plt.vlines(0,ymin=-4, ymax=10, colors='#888888', linestyles='dotted')
 
plt.subplot(2,1,2)
plt.title('正規化')
plt.xlim([-4, 10])
plt.ylim([-4, 10])
plt.scatter(data[:, 0], data[:, 1], c='red', marker='x', s=30, label='スケール前')
plt.scatter(data_norm[:, 0], data_norm[:, 1], c='green', marker='x', s=30, label='正規化')
plt.legend(loc='upper left')
plt.hlines(0,xmin=-4, xmax=10, colors='#888888', linestyles='dotted')
plt.vlines(0,ymin=-4, ymax=10, colors='#888888', linestyles='dotted')
plt.show()




データフレームの正規化...

・特定の列だけ正規化するとき

>>> import pandas as pd
>>> from sklearn.preprocessing import MinMaxScaler
>>> scaler = MinMaxScaler()
>>> dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],
                           'B':[103.02,107.26,110.35,114.23,114.68],
                           'C':[23.76,10.26,10.35,14.31,42.81],
                           'D':['big','small','big','small','small']})

>>> dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A', 'B']]) # A, Bカラムのみを正規化
# dfTest.loc[:,['A', 'B']] = scaler.fit_transform(dfTest[['A', 'B']]) でも可
>>> dfTest
          A         B      C      D
0  0.000000  0.000000  23.76    big
1  0.926219  0.363636  10.26  small
2  0.935335  0.628645  10.35    big
3  1.000000  0.961407  14.31  small
4  0.938495  1.000000  42.81  small


・すべての列を正規化するとき

>>> dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],
                           'B':[103.02,107.26,110.35,114.23,114.68],
                           'C':[23.76,10.26,10.35,14.31,42.81]})
>>> dfTest
       A       B      C
0  14.00  103.02  23.76
1  90.20  107.26  10.26
2  90.95  110.35  10.35
3  96.27  114.23  14.31
4  91.21  114.68  42.81
>>> dfTest.loc[:,:] = scaler.fit_transform(dfTest) # 全カラムを正規化
>>> dfTest
          A         B         C
0  0.000000  0.000000  0.414747
1  0.926219  0.363636  0.000000
2  0.935335  0.628645  0.002765
3  1.000000  0.961407  0.124424
4  0.938495  1.000000  1.000000


・注意点

直接代入するとデータフレームからndarrayになってカラムが消える。

>>> dfTest = scaler.fit_transform(dfTest) # dfTestに直接代入
>>> dfTest
array([[0.        , 0.        , 0.41474654],
       [0.92621855, 0.36363636, 0.        ],
       [0.93533487, 0.62864494, 0.00276498],
       [1.        , 0.96140652, 0.12442396],
       [0.9384952 , 1.        , 1.        ]])

>>> dfTest.columns
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'numpy.ndarray' object has no attribute 'columns'


理由は、fit_transformされたオブジェクトはndarrayだから!

>>> type(scaler.fit_transform(dfTest))
<class 'numpy.ndarray'>


たとえ、全ての列を正規化したくても、DataFrame.locなどを使って代入する