updated on 2019-12-03
Exelファイルを正規化する。(筆者は多重回帰分析を行う)
正規化をすると、値が意味する絶対量を相対量に変換するため、単位が関係なくなり、各因子の係数(偏回帰係数)が、「寄与率」のように比較できる。
また、私の場合、大学生の期末試験のデータを扱ったりしましたが、試験の満点が各学科で違ったりしても、正規化することで他の学科との平等な生徒の比較ができるようになる。
Min-Max Normalization。
$$ x'= \frac{ x - min(x) }{ max(x) - min(x) } $$
平均をμ, 標準偏差をσとする
$$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
>>> 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 の StandardScaler と MinMaxScaler がそれぞれ 標準化 と 正規化 のモジュールです。主に使うメソッドは次の 3 つです。
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],
# dfTest.loc[:,['A', 'B']] = scaler.fit_transform(dfTest[['A', 'B']]) でも可
'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
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'
>>> type(scaler.fit_transform(dfTest)) <class 'numpy.ndarray'>
たとえ、全ての列を正規化したくても、DataFrame.locなどを使って代入する