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

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

正規分布について

連続型確率分布には正規分布と呼ばれる分布があります。正規分布は、検定や推定など様々な場面で用いられます。この記事では、pythonを使った正規分布ついて解析的に求める場合と、数値的に求める場合について紹介しています。

正規分布とは

正規分布とは、連続型確率分布の一つで、統計学における検定や推定、モデル作成などで用いられます。また、多くの統計的手法において、正規分布に従うことを仮定します。

正規分布に従う確率変数の確率密度関数の式

正規分布に従う確率変数Xの確率密度関数f(x)は次の式で表されます。


f(x) = \frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}} \quad (-\infty < x < \infty)

または、eのかわりにexpを使うと以下のようになります。


f(x) = \frac{1}{\sqrt{2\pi}\sigma}exp\Bigl(-\frac{(x-\mu)^2}{2\sigma^2}\Bigr) \quad (-\infty < x < \infty)

標準正規分布に従う確率変数の確率密度関数の式

正規分布の中で、特に平均mu=0、分散sigma2=1である正規分布を「標準正規分布」といいます。先ほどの正規分布の式に平均mu=0、分散sigma2=1を代入すると以下のようになります。


f(x) = \frac{1}{\sqrt{2\pi}}e^{-\frac{x^2}{2}} \quad (-\infty < x < \infty)

または


f(x) = \frac{1}{\sqrt{2\pi}}exp\Bigl(-\frac{x^2}{2}\Bigr) \quad (-\infty < x < \infty)

ネイピア数を使った正規分布のグラフの描き方

ここでは、ネイピア数を用いた正規分布を描画しています。やり方としては、numpyで0から100までの間に、10000の分割データを用意し、そのデータをネイピア数で表した正規分布の式で計算した結果をプロットしています。この時の正規分布は平均50、標準偏差10で計算しています。

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)))

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

f:id:hira03:20200210152606p:plain
statistics_normal_distribution_e

expを使った正規分布のグラフの描き方

expを用いた正規分布の場合は、ネイピア数の時と同じように、numpyでデータを用意します。expの場合は、numpyの一つ一つのデータに対して計算する必要があるので、for文で処理しています。

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

x2 = -(((x - mu)**2)/(2*s**2))
fx = np.array([(1/math.sqrt(2*pi)*s)*math.exp(i) for i in x2])

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

f:id:hira03:20200210152638p:plain
statistics_normal_distribution_exp

random.gaussを使った正規分布の描き方

乱数を生成できるrandomにはガウス分布正規分布と同じ意味)を生成できるrandom.gaussがあります。これを使うと、正規分布にしたがったデータを生成することができます。random.gaussには平均と標準偏差の引数を設定できます。生成したデータをヒストグラムで可視化すると、先ほどの解析的に生成した正規分布のグラフとほぼ重なることがわかります。

import random
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)))

normals = [random.gauss(mu, s) for i in range(10000)]

fig, axes = plt.subplots(figsize = (12, 8))
plt.hist(normals, 40, density = True)
plt.plot(x, 0.01*fx)
plt.show()

f:id:hira03:20200210152715p:plain
statistics_normal_distribution_gauss

random.normalvariateを使った正規分布の描き方

random.normalvariateを使うことでも、正規分布に従ったデータを生成することができます。生成したデータをヒストグラムで可視化すると、こちらも解析的に生成した正規分布のグラフとほぼ重なることがわかります。

import random
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)))

normals = [random.normalvariate(mu, s) for i in range(10000)]

fig, axes = plt.subplots(figsize = (12, 8))
plt.hist(normals, 40, density = True)
plt.plot(x, 0.01*fx)
plt.show()

f:id:hira03:20200210152755p:plain
statistics_normal_distribution_normalvariate

numpy.random.normalを使った正規分布の描き方

numpyにも、乱数を生成する機能があります。numpy.random.normalを使うと、正規分布に従ったデータを生成することができます。numpy.random.normalの場合は、平均と標準偏差と生成するデータ数を指定するだけで正規分布に従うデータを生成することができます。

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

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

normals = np.random.normal(mu , s, size)

fig, axes = plt.subplots(figsize = (12, 8))
plt.hist(normals, 40, density = True)
plt.plot(x, 0.01*fx)
plt.show()

f:id:hira03:20200210152840p:plain
statistics_normal_distribution_normal

scipy.stats.normを使った正規分布の描き方

scipy.stats.normを使用すると正規分布を簡単に描くことができます。この場合は、numpyで0から100までのデータを10000作り、norm.pdfで引数を設定することで正規分布の結果を得ることができます。必要な引数はnumpyデータと平均(loc)、標準偏差(scale)となっています。

from scipy.stats import norm

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

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

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

f:id:hira03:20200210152909p:plain
statistics_normal_distribution_norm

参考

統計学の時間 | 統計WEB