データ分析系プログラマーのブログ

主にPythonを使ったデータ分析や機械学習をやっています。

標準化について

正規分布に従う確率変数は、標準化を行うことによって標準正規分布に従う確率変数に変換することができます。標準化したデータは、異なる分布のデータ同士を比較したりすることができます。この記事では、pythonを使った標準化の方法について紹介しています。

標準化とは

ある確率変数Xが平均mu、分散sigma2正規分布に従う時、から平均muを引いて標準偏差sigmaで割った値をzとおくと、zは「平均が0、分散が1の標準正規分布」に従います。このような計算を標準化と呼び、以下のようにあらわします。標準化を行うことで単位や平均値が異なるデータ同士を比較できるようになります。


z = \frac{X-\mu}{\sigma}

例えば、あるクラスの数学と国語のテストの結果が以下のような場合、 ・数学 平均点:55点 標準偏差:15点 ・国語 平均点:45点 標準偏差:10点 A君は、数学が85点、国語が80点だった時、どちらの教科の方が順位が上かを比較するには以下のようにします。


z_m = \frac{X-\mu}{\sigma} = \frac{85-55}{15} = 2

z_j = \frac{X-\mu}{\sigma} = \frac{80-45}{10} = 3.5

この場合は、標準化した数値が大きい方が順位が上なので、国語の方が順位が上であることがわかります。

偏差値とは

偏差値は「平均が50点、標準偏差が10点」となるように、標準化した値zに10をかけて50を足したものです。


50 + 10 \times z

例えば、先ほどのA君の数学と国語の得点から偏差値を計算すると以下のようになります。

・数学の偏差値:50+10×2=70 ・国語の偏差値:50+10×3.5=85

Pythonを使った標準化の例その1(meanとpstdev)

以下の例では、random.randintを使って0から100までの整数をランダムに50個生成したデータを使って標準化の変換を行っています。標準化を行うためには、そのデータの平均と標準偏差を求める必要があります。以下では、statisticsのmeanとpstdevを使って平均と標準偏差を計算しています。このデータを標準化した結果、12番目にある88のデータは標準化することによって、約1.273となりました。また、このデータを点数とした場合、88の偏差値は約62.73と計算されました。

import random
data = [random.randint(0, 100) for i in range(50)]
print(data)
[28, 11, 73, 17, 44, 15, 4, 11, 60, 21, 100, 88, 28, 66, 61, 34, 16, 18, 66, 20, 95, 96, 100, 94, 76, 3, 81, 17, 30, 53, 84, 23, 97, 13, 89, 75, 50, 88, 16, 42, 40, 22, 11, 45, 26, 77, 42, 20, 86, 56]
from statistics import mean
from statistics import pstdev

mu = mean(data)
s = pstdev(data)
print("平均 = ", mu, "標準偏差", s)

平均 = 48.56 標準偏差 30.977514425789554

z = (data[11] - mu)/s
print(z)

1.2731815554305808

dev = 50 + 10*z
print(dev)

62.73181555430581

Pythonを使った標準化の例その2(zscore)

標準化の計算には、その他にもあります。例えば、scipyのzscoreを使用することによって、与えられたデータ(numpy形式の必要がある)から自動的に平均と標準偏差を求めて、標準化を行います。実際に標準化されたデータを確認してみると、88だったデータは、約1.273となりました。

from scipy.stats import zscore
arr_data = np.array(data)
data_std = zscore(arr_data)
print(data_std[11])

1.2731815554305808

Pythonを使った標準化の例その3(StandardScaler)

sklearnのStandardScalerを使うことでも、データを標準化することができます。StandardScalerは、機械学習を行う際の前処理などでもよく使用するライブラリです。この場合も、リスト形式のデータをnumpyに変換することで、StandardScalerを実行することができます。結果は他と同じように約1.273となっています。

import numpy as np
from sklearn.preprocessing import StandardScaler

arr_data = np.array(data)
arr_data = arr_data.reshape(-1, 1)
sc = StandardScaler()
data_std = sc.fit_transform(arr_data)
print(data_std[11])

[1.27318156]

標準化したデータを描画する

以下の例は、numpyによって生成したデータを使って、平均が50、標準偏差が10に従う正規分布の確率変数を標準化して描画しています。標準化の方法は、標準化の式を使用して、平均を50、標準偏差が10という設定で計算した場合のものがあります。その次の例では、StandardScalerを使って、標準化を行っていますが、この場合は、StandardScalerは与えられたデータから平均と標準偏差を求めて標準化するため、xは最初の例とは異なる値になってしまいます。先後の例は、scipyのnormを使って、平均50、標準偏差10の正規分布を生成し、xの値を標準化したデータで描画しています。この場合は、最初のグラフと同じ結果になります。

import numpy as np
import math
import matplotlib.pyplot as plt

x = np.linspace(0, 100, 10000)
e = math.e
pi = math.pi
mu = 50
s = 10

fx = (1/math.sqrt(2*pi)*s)*e**(-(((x - mu)**2)/(2*s**2)))
x_std = (x - mu)/s

fig, axes = plt.subplots(figsize = (12, 8))
plt.plot(x_std, fx)
plt.show()

f:id:hira03:20200211132335p:plain
statistics_standardization_distribution_e

import numpy as np
import math
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler

x = np.linspace(0, 100, 10000)
e = math.e
pi = math.pi
mu = 50
s = 10

fx = (1/math.sqrt(2*pi)*s)*e**(-(((x - mu)**2)/(2*s**2)))

x = x.reshape(-1, 1)
sc = StandardScaler()
x_std = sc.fit_transform(x)

fig, axes = plt.subplots(figsize = (12, 8))
plt.plot(x_std, fx)
plt.show()

f:id:hira03:20200211132411p:plain
statistics_StandardScaler_distribution_e

from scipy.stats import norm

x = np.linspace(0, 100, 10000)
mu = 50
s = 10

x_std = (x - mu)/s
fx = norm.pdf(x, loc=mu, scale=s)

fig, axes = plt.subplots(figsize = (12, 8))
plt.plot(x_std, fx*100)
plt.show()

f:id:hira03:20200211132442p:plain
statistics_standard_normal_distribution_e

参考

統計学の時間 | 統計WEB