SciPy.stats#

in English or the language of your choice.

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

# 警告メッセージを非表示
import warnings
warnings.filterwarnings("ignore")

SciPy(サイパイ)は,NumPyの大幅な拡張版と理解して良い。SciPyを読み込むとNumPyの関数などを利用できるようになる。しかしSciPyは大きなパッケージであり,全てを読み込む必要もない。従って,NumPyを読み込んで,SciPyのサブパッケージや関数を読み込むということで十分であろう。ここではSciPystatsというサブパッケージについて説明する。

正規分布(Normal Distribution)#

正規分布のモジュール名はnormであり,以下が主な関数である。

  1. 確率密度関数: norm.pdf(x, loc=0, scale=1)

    • pdfはProbability Density Functionの頭文字

    • loc = 平均

    • scale = 標準偏差

    • x = \(-\infty\)から\(\infty\)の間の値

    • 返り値:xの値が発生する確率(%)

    • locscaleを省略すると標準正規分布の確率密度関数となる。

  2. 累積分布関数: norm.cdf(x, loc=0, scale=1)

    • cdfはCumulative Distribution Functionの頭文字

    • loc = 平均

    • scale = 標準偏差

    • x = \(-\infty\)から\(\infty\)の間の値

    • 返り値:x以下の値が発生する確率(%)

    • locscaleを省略すると標準正規分布の累積分布関数となる。

  3. パーセント・ポイント関数: norm.ppf(a, loc=0, scale=1)

    • ppfはPercent Point Functionの頭文字

    • loc = 平均

    • scale = 標準偏差

    • a = 0 ~ 1の間の値

    • 返り値:累積分布関数の値がaである場合のxの値(累積分布関数の逆関数)

    • locscaleを省略すると標準正規分布のパーセント・ポイント関数となる。

  4. ランダム変数生成関数: norm.rvs(loc=0, scale=1, size=1)

    • rvsはRandom VariableSの大文字の部分

    • loc = 平均

    • scale = 標準偏差

    • size = 生成されるランダム変数の数

    • 返り値:正規分布に従って発生したランダム変数

    • locscaleを省略すると標準正規分布のランダム変数生成関数となる。

scipy.statsnormを読み込む。

from scipy.stats import norm

確率密度関数

norm.pdf(0)
0.3989422804014327

0が発生する確率は約39.9%とわかる。norm.pdf(x)のグラフを描くためには,\(\infty\)から\(\infty\)xの返り値が必要になるが,ここでは-4から4の区間で100個のxの値で近似する。

x = np.linspace(-4, 4, 100)

このxを直接norm.pdf()に代入すると,全てのxの値に対しての返り値を得ることができる。それをy_pdfに割り当てる。

y_pdf = norm.pdf(x)  # 標準正規分布
plt.plot(x,y_pdf)
plt.xlabel('x')
plt.ylabel('p')
plt.title('Standard Normal Distribution')
pass
_images/ecd1cd06ec16a0a0a4a3560f493027bc37d97645c72266000edc32cbb8d89d35.png

累積分布関数

y_cdf = norm.cdf(x)  # 標準正規分布
plt.plot(x, y_cdf)
plt.xlabel('x')
plt.ylabel('P')
plt.title('Cumulative Distribution Function')
pass
_images/7a323cef63dbc0d1ef4e96e3cd577a22fe036cde756915f6e1b4b4ae6a9687ec.png

この関数を使うことにより,xの値が\(X\)の時,それ以下の値が発生する確率は何%かを計算できる。例えば,x\(0\)以下の値を取る確率は

norm.cdf(0)
0.5

確率密度関数が平均\(0\)loc=0)を中心に左右対称のため確率は50%となる。では,x\(-4\)以下の場合は?

norm.cdf(-4)
3.167124183311986e-05

返り値の最後のe-05\(\times 10^-5\)という意味。では,xが4以上の確率は?

1-norm.cdf(4)
3.167124183311998e-05

パーセント・ポイント関数

p = np.linspace(0,1,100)
y_ppf = norm.ppf(p)  # 標準正規分布
plt.plot(p,y_ppf)
plt.xlabel('P')
plt.ylabel('x')
plt.title('Percent Point Function')
pass
_images/f676bc9bf4f0df514659bbad4c713cea940e2ab4f70163b92f917f298b9aad9d.png

パーセント・ポイント関数を使い,累積分布関数の値がPである場合のxの値を計算できる。P=0.5の場合のxは?

norm.ppf(0.5)
0.0

P=0.025の場合のxは?

norm.ppf(0.025)
-1.9599639845400545

P=0.975の場合のxは?

norm.ppf(0.975)
1.959963984540054

ランダム変数生成関数

10000個のランダム変数を生成しよう。

y_rvs = norm.rvs(size=10_000)  # 標準正規分布
plt.hist(y_rvs, bins=30)  #  bins=表示する棒の数(デフォルトは10)
pass
_images/d7b87e05cb6ecb697e19fee85e5b77de237f65d733277529c94a6e87c85e7b91.png

y_rvsは標準正規分布から生成されたが,y_rvsがどの分布関数から生成されたか不明だったとしよう。更に,y_rvsから元の確率密度関数を推定したいとしよう。その際に使う手法をカーネル密度推定と呼ぶ。SciPyにはそのための関数gaussian_kdeが用意されている。gaussian(ガウシアン)とは天才数学者ガウスの名前からきており「ガウス的な」と理解すれば良い。kdeはKernel Density Estimate(カーネル密度推定)の頭文字をとっている。

from scipy.stats import gaussian_kde  # サブパッケージを読み込む
kde = gaussian_kde(y_rvs)  # y_rvsから確率密度関数を推定
plt.plot(x, kde(x))        # 横軸のxに対してプロット
pass
_images/51613cbf12d3833fabbae0dec477f7a96826cd3565c09b04cfe14c27e949f5cc.png

推定なので標準正規分布の確率密度関数と全く同じにはならないが,非常に近い。上の図と重ねると。

plt.hist(y_rvs, bins=30, density=True)
plt.plot(x, kde(x))
pass
_images/b2de29f8ef3a65a90e3e45560ad02460d6d727fc8efcda0cd43f5abafe7fed64.png

plt.hist()にあるdensity=Trueは縦軸を%表示にする引数である。これによりplt.histのヒストグラムとplt.plot()のカーネル密度関数が同じスケールで表示されることになる。

その他の分布関数#

\(t\)分布#

\(t\)分布のモジュール名はt

t.pdf(x, df)
t.cdf(x, df)
t.ppf(a, df)
t.rvs(df, size=1)
  • df:自由度(degree of freedom)

scipy.statstを読み込み確率密度関数の図を表示する。

from scipy.stats import t

x = np.linspace(-4,4,100)
y = t.pdf(x, df=1)
plt.plot(x,y)
pass
_images/332e496ec8cad9ea71e3b9ffbb86669d12538eb713e2d47aa5854a86e2939ff3.png

df=1の場合にxの値が-3以下の確率は何か?

t.cdf(-3, df=1)
0.10241638234956672

df=1の場合にxの値が3以上の確率は何か?

1-t.cdf(3, df=1)
0.10241638234956674

\(t\)分布と標準正規分布は正規分布は非常に類似性が高い。自由度が30になれば,両分布の誤差は非常に小さくなることが知られている。確認するために,プロットしてみよう。

x = np.linspace(-4, 4, 100)
plt.plot(x, t.pdf(x, 30), label=r'$t$ 分布')
plt.plot(x, norm.pdf(x), label='標準正規分布')
plt.legend()
pass
_images/109a9e49ca422c103e85bdebd98a3d24455182ea7506c8b33eb2b7c5df8991fd.png

\(\chi^2\)分布#

\(\chi^2\)分布のモジュール名はchi2

chi2.pdf(x, df)
chi2.cdf(x, df)
chi2.ppf(a, df)
chi2.rvs(df, size=1)
  • df:自由度(degree of freedom)

scipy.statschi2を読み込み確率密度関数の図を表示する。

from scipy.stats import chi2
x = np.linspace(0,12,100)
y = chi2.pdf(x, df=3)
plt.plot(x,y)
pass
_images/6b8fdcf9e9049512679ae718d4056d3922f25382c3b9298fb4ef96232475b08f.png

df=3の場合にxの値が1以下の確率は何か?

chi2.cdf(1, df=3)
0.19874804309879915

df=3の場合にxの値が10以上の確率は何か?

1-chi2.cdf(10, df=3)
0.0185661354630432

\(F\)分布#

\(F\)分布のモジュール名はf

f.pdf(x, dfn, dfd)
f.cdf(x, dfn, dfd)
f.ppf(a, dfn, dfd)
f.rvs(dfn, dfd, size=1)
  • dfn:分子の自由度(numerator degree of freedom)

  • dfd:分母自由度(denominator degree of freedom)

scipy.statsfを読み込み確率密度関数の図を表示する。

from scipy.stats import f
x = np.linspace(0.001,5,1000)
y = f.pdf(x, dfn=5, dfd=1)
plt.plot(x,y)
pass
_images/9accb6b05392542f2a46562a1bcb0810d63dced2a51d18ffe180aeda1c159f34.png

dfn=5, dfd=1の場合にxの値が0.1以下の確率は何か?

f.cdf(0.1, dfn=5, dfd=1)
0.02503101581845294

dfn=5, dfd=1の場合にxの値が5以上の確率は何か?

1-f.cdf(5, dfn=5, dfd=1)
0.32657156446244606

一様分布 (Uniform Distribution)#

一様分布のモジュール名はuniform

uniform.pdf(x, loc=0, scale=1)
uniform.cdf(x, loc=0, scale=1)
uniform.ppf(a, loc=0, scale=1)
uniform.rvs(loc=0, scale=1, size=1)
  • locxの最小値

  • scalexの幅

    • xの最大値:loc+scale

  • mだけ「右」に平行移動させる場合は

loc=m   # scaleは省略

scipy.statsuniformを読み込み確率密度関数の図を表示する。

from scipy.stats import uniform
x = np.linspace(0,12,100)
y = uniform.pdf(x, loc=1, scale=9)
plt.plot(x,y)
pass
_images/fe839c3fa8d84acc1d93800d3dbec34074f3fc2c0577e3392fe50f3c464bae1f.png

ロジスティク分布(Logistic Distribution)#

ロジスティック分布のモジュール名はlogistic

logistic.pdf(x, loc=0, scale=1)
logistic.cdf(x, loc=0, scale=1)
logistic.ppf(a, loc=0, scale=1)
logistic.rvs(loc=0, scale=1, size=1)
  • loc:平均値

  • scale:分散に影響する値

logistic.pdf(x,loc,scale) = logistic.pdf(z), z=(x-loc)/scale

scipy.statslogisticを読み込み確率密度関数の図を表示する。

from scipy.stats import logistic
x = np.linspace(-5,5,100)
y = logistic.pdf(x)
plt.plot(x,y)
pass
_images/92910c4be0a4319b560edf042893f8dabbb6b872e54d58dc41c81996deeeb760.png