ブログ

Ch.13 「回帰分析」の章末問題の解答例 〜基礎統計学Ⅰ 統計学入門(東京大学出版会)〜

当記事は「基礎統計学Ⅰ 統計学入門(東京大学出版会)」の読解サポートにあたってChapter.13の「回帰分析」の章末問題の解説について行います。
※ 基本的には書籍の購入者向けの解説なので、まだ入手されていない方は下記より入手をご検討ください。また、解説はあくまでサイト運営者が独自に作成したものであり、書籍の公式ページではないことにご注意ください。(そのため著者の意図とは異なる解説となる可能性はあります)

・解答まとめ
https://www.hello-statisticians.com/answer_textbook_stat_basic_1-3#red

章末の演習問題について

問題13.1の解答例

i)
下記を実行することで散布図を作成することができる。

import numpy as np
import matplotlib.pyplot as plt

x = np.array([2., 2., 2., 2., 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 3., 3., 3., 3., 3., 3., 3., 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 4., 4., 4., 4., 4., 4., 4., 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 5., 5., 5., 5., 5., 5., 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 6., 6., 6., 6., 6., 6.5, 6.5, 6.5, 6.5, 7.])
y = np.array([2., 2.5, 2.5, 3., 2., 2.5, 3., 3., 3., 3.5, 2.5, 3., 3., 3.5, 3.5, 4., 4.5, 3., 3.5, 4., 4.5, 5., 5.5, 3.5, 4., 4.5, 4.5, 5., 5.5, 5.5, 4., 4.5, 5., 5., 5.5, 5.5, 6., 4.5, 5., 5.5, 6., 6.5, 5., 5.5, 5.5, 6., 6.5, 7., 5.5, 5.5, 6., 6.5, 7., 5.5, 6.5, 7., 7., 7.5])

plt.scatter(x,y)
plt.show()

ⅱ)
$y_i = \beta_{0} + \beta_{1} x_i$のように回帰式を定義したとき、係数の$\beta_{0}, \beta_{1}$は下記を実行することで計算できる。

import numpy as np
import matplotlib.pyplot as plt

beta = np.zeros(2)
x_ = np.arange(1., 8., 0.1)

x = np.array([2., 2., 2., 2., 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 3., 3., 3., 3., 3., 3., 3., 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 4., 4., 4., 4., 4., 4., 4., 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 5., 5., 5., 5., 5., 5., 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 6., 6., 6., 6., 6., 6.5, 6.5, 6.5, 6.5, 7.])
y = np.array([2., 2.5, 2.5, 3., 2., 2.5, 3., 3., 3., 3.5, 2.5, 3., 3., 3.5, 3.5, 4., 4.5, 3., 3.5, 4., 4.5, 5., 5.5, 3.5, 4., 4.5, 4.5, 5., 5.5, 5.5, 4., 4.5, 5., 5., 5.5, 5.5, 6., 4.5, 5., 5.5, 6., 6.5, 5., 5.5, 5.5, 6., 6.5, 7., 5.5, 5.5, 6., 6.5, 7., 5.5, 6.5, 7., 7., 7.5])

beta[1] = np.sum((x-np.mean(x))*(y-np.mean(y)))/np.sum((x-np.mean(x))**2)
beta[0] = np.mean(y) - beta[1]*np.mean(x)

print("beta_0: {:.3f}, beta_1:{:.3f}".format(beta[0], beta[1]))

plt.scatter(x, y, color="green")
plt.plot(x_, beta[0]+beta[1]*x_)
plt.show()

・実行結果

> print("beta_0: {:.3f}, beta_1:{:.3f}".format(beta[0], beta[1]))
beta_0: 0.726, beta_1:0.932

ⅲ)
$y_i = \beta_{0} + \beta_{1} x_i$のように考えるとき、推定結果と$(13.14), (13.16)$式より、回帰式の傾きに関する検定統計量$t$は下記のように計算できる。
$$
\large
\begin{align}
t &= \frac{\hat{\beta}_1-0.9}{s.e.(\hat{\beta}_1)} \quad (13.16) \\
s.e.(\hat{\beta}_1) &= \frac{\sqrt{\sum_{i=1}^{n} \hat{\epsilon}_{i}^{2}/n-2}}{\sqrt{\sum_{i=1}^{n} (x_i-\bar{x})^2}} \quad (13.14)
\end{align}
$$

ここで検定統計量$t$が自由度$n-2$の$t$分布$t(n-2)$に従うことを元に有意水準$5$%の検定を行えばよい。

上記に基づいて以下を実行することで結果を得ることができる。

import numpy as np
from scipy import stats

beta = np.zeros(2)

x = np.array([2., 2., 2., 2., 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 3., 3., 3., 3., 3., 3., 3., 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 4., 4., 4., 4., 4., 4., 4., 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 5., 5., 5., 5., 5., 5., 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 6., 6., 6., 6., 6., 6.5, 6.5, 6.5, 6.5, 7.])
y = np.array([2., 2.5, 2.5, 3., 2., 2.5, 3., 3., 3., 3.5, 2.5, 3., 3., 3.5, 3.5, 4., 4.5, 3., 3.5, 4., 4.5, 5., 5.5, 3.5, 4., 4.5, 4.5, 5., 5.5, 5.5, 4., 4.5, 5., 5., 5.5, 5.5, 6., 4.5, 5., 5.5, 6., 6.5, 5., 5.5, 5.5, 6., 6.5, 7., 5.5, 5.5, 6., 6.5, 7., 5.5, 6.5, 7., 7., 7.5])

beta[1] = np.sum((x-np.mean(x))*(y-np.mean(y)))/np.sum((x-np.mean(x))**2)
beta[0] = np.mean(y) - beta[1]*np.mean(x)

epsilon = y-(beta[0]+beta[1]*x)
s = np.sqrt(np.sum(epsilon**2)/(x.shape[0]-2.))

s_beta1 = s/np.sqrt(np.sum((x-np.mean(x))**2))
t = (beta[1]-0.9)/s_beta1

if t < stats.t.ppf(0.025,x.shape[0]-2) or stats.t.ppf(0.975,x.shape[0]-2) < t:
    print("t: {:.3f}, {} H_0".format(t,"reject"))
else:
    print("t: {:.3f}, {} H_0".format(t,"accept"))

・実行結果

t: 0.513, accept H_0

上記より、帰無仮説$H_0: \beta_{1}=0.9$は棄却されない。

iv)
推定値$\hat{y}_i$に対する誤差項$\hat{\epsilon}_i$の分散の推定量を$s^2$とおき、$(13.8)$式の$\displaystyle s^2 = \sum_{i=1}^{n} \frac{\hat{\epsilon}_{i}^{2}}{n-2}$を計算し、$2s.e.$以上の外れ値があるかの確認を行う。

計算にあたっては以下を実行すれば良い。

import numpy as np

beta = np.zeros(2)

x = np.array([2., 2., 2., 2., 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 3., 3., 3., 3., 3., 3., 3., 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 4., 4., 4., 4., 4., 4., 4., 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 5., 5., 5., 5., 5., 5., 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 6., 6., 6., 6., 6., 6.5, 6.5, 6.5, 6.5, 7.])
y = np.array([2., 2.5, 2.5, 3., 2., 2.5, 3., 3., 3., 3.5, 2.5, 3., 3., 3.5, 3.5, 4., 4.5, 3., 3.5, 4., 4.5, 5., 5.5, 3.5, 4., 4.5, 4.5, 5., 5.5, 5.5, 4., 4.5, 5., 5., 5.5, 5.5, 6., 4.5, 5., 5.5, 6., 6.5, 5., 5.5, 5.5, 6., 6.5, 7., 5.5, 5.5, 6., 6.5, 7., 5.5, 6.5, 7., 7., 7.5])

beta[1] = np.sum((x-np.mean(x))*(y-np.mean(y)))/np.sum((x-np.mean(x))**2)
beta[0] = np.mean(y) - beta[1]*np.mean(x)

epsilon = y-(beta[0]+beta[1]*x)
s = np.sqrt(np.sum(epsilon**2)/(x.shape[0]-2.))

for i in range(x.shape[0]):
    if 2*s-np.abs(epsilon[i])<0:
        print("Outlier: Idx {} ({},{})".format(i+1,x[i],y[i]))

・実行結果

Outlier: Idx 23 (3.5,5.5)

上記より$2s.e.$以上の外れ値が存在することが確認できる。

v)
ⅱ)で計算したbeta[0]beta[1]を用いて、下記を実行すれば良い。

print(beta[0]+beta[1]*8.)

・実行結果

> print(beta[0]+beta[1]*8.)
8.18575023592

問題13.2の解答例

i)
下記を実行することで、散布図を作成することができる。

import numpy as np
import matplotlib.pyplot as plt

x = np.array([229., 367., 301., 352., 457., 427., 485., 616., 695., 806., 815., 826., 951., 1202., 881., 827., 1050., 1127., 1241., 1330., 1158., 1254., 1243., 1216., 1368., 1231., 1219., 1284., 1355.])
y = np.array([61.2, 70.0, 74.9, 82.8, 93.6, 98.5, 108.8, 120.1, 135.1, 152.5, 165.8, 173.0, 189.9, 202.6, 199.7, 205.0, 214.9, 226.3, 238.1, 250.7, 261.4, 271.0, 279.3, 288.4, 303.0, 317.3, 325.7, 340.3, 359.5])

plt.scatter(x,y)
plt.show()

・実行結果

上記より、概ね正の相関があると考えることができる。

ⅱ)
下記を実行することで弾性値を推定することができる。

import numpy as np

beta = np.zeros(2)

x = np.array([61.2, 70.0, 74.9, 82.8, 93.6, 98.5, 108.8, 120.1, 135.1, 152.5, 165.8, 173.0, 189.9, 202.6, 199.7, 205.0, 214.9, 226.3, 238.1, 250.7, 261.4, 271.0, 279.3, 288.4, 303.0, 317.3, 325.7, 340.3, 359.5])
y = np.array([229., 367., 301., 352., 457., 427., 485., 616., 695., 806., 815., 826., 951., 1202., 881., 827., 1050., 1127., 1241., 1330., 1158., 1254., 1243., 1216., 1368., 1231., 1219., 1284., 1355.])

log_x = np.log(x)
log_y = np.log(y)

beta[1] = np.sum((log_x-np.mean(log_x))*(log_y-np.mean(log_y))) / np.sum((log_x-np.mean(log_x))**2)
beta[0] = np.mean(log_y) - beta[1]*np.mean(log_x)

print("Estimated beta_1: {:.3f}".format(beta[1]))

・実行結果

> print("Estimated beta_1: {:.3f}".format(beta[1]))
Estimated beta_1: 0.967

ⅲ)

ratio = 1.04**12
y_pred = 1355.*ratio*beta[1]

print(y_pred)

・実行結果

> print(y_pred)
2097.52451479

上記は巻末の解答とは異なる結果だが詳細の計算方法がわからないので、それほど大きく異ならないことからここでは許容した。

iv)
推定結果と$(13.14), (13.16)$式より、回帰式の傾きに関する検定統計量$t$は下記のように計算できる。
$$
\large
\begin{align}
t &= \frac{\hat{\beta}_1-1}{s.e.(\hat{\beta}_1)} \quad (13.16) \\
s.e.(\hat{\beta}_1) &= \frac{\sqrt{\sum_{i=1}^{n} \hat{\epsilon}_{i}^{2}/n-2}}{\sqrt{\sum_{i=1}^{n} (x_i-\bar{x})^2}} \quad (13.14)
\end{align}
$$

ここで検定統計量$t$が自由度$n-2$の$t$分布$t(n-2)$に従うことを元に帰無仮説$H_0: \beta_{1}=1$に対し、有意水準$5$%の検定を行えばよい。

上記に基づいて以下を実行することで結果を得ることができる。

import numpy as np
from scipy import stats

beta = np.zeros(2)

x = np.array([61.2, 70.0, 74.9, 82.8, 93.6, 98.5, 108.8, 120.1, 135.1, 152.5, 165.8, 173.0, 189.9, 202.6, 199.7, 205.0, 214.9, 226.3, 238.1, 250.7, 261.4, 271.0, 279.3, 288.4, 303.0, 317.3, 325.7, 340.3, 359.5])
y = np.array([229., 367., 301., 352., 457., 427., 485., 616., 695., 806., 815., 826., 951., 1202., 881., 827., 1050., 1127., 1241., 1330., 1158., 1254., 1243., 1216., 1368., 1231., 1219., 1284., 1355.])

log_x = np.log(x)
log_y = np.log(y)

beta[1] = np.sum((log_x-np.mean(log_x))*(log_y-np.mean(log_y))) / np.sum((log_x-np.mean(log_x))**2)
beta[0] = np.mean(log_y) - beta[1]*np.mean(log_x)

epsilon = log_y-(beta[0]+beta[1]*log_x)
s = np.sqrt(np.sum(epsilon**2)/(x.shape[0]-2.))

s_beta1 = s/np.sqrt(np.sum((log_x-np.mean(log_x))**2))
t = (beta[1]-1.)/s_beta1

if t < stats.t.ppf(0.025,x.shape[0]-2) or stats.t.ppf(0.975,x.shape[0]-2) < t:
    print("t: {:.3f}, {} H_0".format(t,"reject"))
else:
    print("t: {:.3f}, {} H_0".format(t,"accept"))

・実行結果

t: -0.725, accept H_0

上記より、帰無仮説$H_0: \beta_{1}=1$は棄却されない。

まとめ

Ch.2 「ARMA過程」の章末問題の解答例 〜計量時系列分析 朝倉書店〜

当記事は「経済・ファイナンスデータの計量時系列分析(朝倉書店)」の読解サポートにあたってChapter.2の「ARMA過程」の章末問題の解説について行います。

基本的には書籍の購入者向けの解答例・解説なので、まだ入手されていない方は入手の上、ご確認ください。また、解説はあくまでサイト運営者が独自に作成したものであり、書籍の公式ページではないことにご注意ください。(そのため著者の意図とは異なる解説となる可能性はあります)

また、下記に公式の解答があるので、こちらも合わせて参照ください。
https://www.asakura.co.jp/user_data/contents/12792/3.pdf

章末の演習問題について

問題2.1の解答例

問題2.2の解答例

・定常なモデル
(a)、(b)、(c)、(d)、(e)

・反転可能なモデル
(a)、(d)、(e)、(f)

問題2.3の解答例

$$
\large
\begin{align}
y_t = \mu + \epsilon_{t} + \theta_{1} \epsilon_{t-1} + \theta_{2} \epsilon_{t-2}, \quad \epsilon_{t} \sim W.N.(\sigma^2)
\end{align}
$$

上記で定義された$MA(2)$過程に関して、以下、計算を行う。

$(1)$
$$
\large
\begin{align}
E[Y_t] &= E[\mu + \epsilon_{t} + \theta_{1} \epsilon_{t-1} + \theta_{2} \epsilon_{t-2}] \\
&= E[\mu] = \mu
\end{align}
$$

$(2)$
$$
\large
\begin{align}
\gamma_{0} &= E[(Y_t-E[Y_t])^2] = E[(Y_t-\mu)^2] \\
&= E[(\epsilon_{t} + \theta_{1} \epsilon_{t-1} + \theta_{2} \epsilon_{t-2})^2] \\
&= E[\epsilon_{t}^2] + \theta_{1}^2 E[\epsilon_{t-1}^2] + \theta_{2}^2 E[\epsilon_{t-2}^2] = (1+\theta_{1}^2+\theta_{2}^2) \sigma^2
\end{align}
$$

$(3)$
$$
\large
\begin{align}
\gamma_{1} &= E[(Y_t-E[Y_t])(Y_{t-1}-E[Y_{t-1}])] = E[(Y_t-\mu)(Y_{t-1}-\mu)] \\
&= E[(\epsilon_{t} + \theta_{1} \epsilon_{t-1} + \theta_{2} \epsilon_{t-2})(\epsilon_{t-1} + \theta_{1} \epsilon_{t-2} + \theta_{2} \epsilon_{t-3})] \\
&= \theta_{1} E[\epsilon_{t-1}^2] + \theta_{1} \theta_{2} E[\epsilon_{t-2}^2] = (\theta_{1}+\theta_{1} \theta_{2}) \sigma^2
\end{align}
$$

$(4)$
$$
\large
\begin{align}
\gamma_{2} &= E[(Y_t-E[Y_t])(Y_{t-2}-E[Y_{t-2}])] = E[(Y_t-\mu)(Y_{t-2}-\mu)] \\
&= E[(\epsilon_{t} + \theta_{1} \epsilon_{t-1} + \theta_{2} \epsilon_{t-2})(\epsilon_{t-2} + \theta_{1} \epsilon_{t-3} + \theta_{2} \epsilon_{t-4})] \\
&= \theta_{2} E[\epsilon_{t-2}^2] = \theta_{2} \sigma^2
\end{align}
$$

$(5)$
$j \geq 3$に関して下記が成り立つ。
$$
\large
\begin{align}
\gamma_{j} &= E[(Y_t-E[Y_t])(Y_{t-j}-E[Y_{t-j}])] = E[(Y_t-\mu)(Y_{t-j}-\mu)] \\
&= E[(\epsilon_{t} + \theta_{1} \epsilon_{t-1} + \theta_{2} \epsilon_{t-2})(\epsilon_{t-j} + \theta_{1} \epsilon_{t-j} + \theta_{2} \epsilon_{t-j})] \\
&= 0
\end{align}
$$

問題2.4の解答例

$1)$
定常条件は$|\phi_1|<1$

$2)$
反転可能条件は$|\theta_1|<1$

問題2.5の解答例

問題2.6の解答例

Ch.3 「2次元のデータ」の章末問題の解答例 〜基礎統計学Ⅰ 統計学入門(東京大学出版会)〜

当記事は基礎統計学Ⅰ 統計学入門(東京大学出版会)」の読解サポートにあたってChapter.3の「$2$次元のデータ」の章末問題の解説について行います。
※ 基本的には書籍の購入者向けの解説なので、まだ入手されていない方は下記より入手をご検討ください。また、解説はあくまでサイト運営者が独自に作成したものであり、書籍の公式ページではないことにご注意ください。(そのため著者の意図とは異なる解説となる可能性はあります)

・解答まとめ
https://www.hello-statisticians.com/answer_textbook_stat_basic_1-3#red

章末の演習問題について

問題3.1の解答例

下記を実行することでそれぞれ結果が得られる。

・散布図の作成

import numpy as np
import matplotlib.pyplot as plt

x = np.array([52.8, 71.2, 72.6, 63.7, 81.3, 81.8, 70.9, 74.0, 73.2, 72.9, 66.7, 65.7, 43.7, 55.5, 79.6, 85.7, 75.3, 80.5, 73.0, 77.0, 77.5, 69.2, 60.0, 78.2, 79.5, 61.8, 49.6, 59.6, 72.1, 71.0, 76.3, 72.8, 71.8, 60.7, 67.0, 71.8, 71.2, 68.3, 68.5, 54.8, 76.0, 65.8, 69.4, 66.9, 69.7, 71.2, 59.6])
y = np.array([41.4, 76.3, 59.2, 51.8, 52.5, 53.2, 62.4, 55.0, 57.7, 63.2, 37.5, 48.5, 32.4, 20.5, 47.9, 68.0, 68.5, 52.5, 63.3, 58.8, 59.7, 48.4, 40.7, 51.0, 50.9, 34.3, 25.8, 32.1, 34.4, 55.1, 60.3, 57.0, 45.6, 54.2, 55.1, 55.7, 70.3, 61.8, 47.6, 42.5, 71.3, 55.2, 65.2, 42.9, 54.7, 62.0, 48.2])

plt.scatter(x,y)
plt.show()

・実行結果

得票率をyとする方が良いと思われたので、逆の順序で作成を行った。

・相関係数の計算

x = np.array([52.8, 71.2, 72.6, 63.7, 81.3, 81.8, 70.9, 74.0, 73.2, 72.9, 66.7, 65.7, 43.7, 55.5, 79.6, 85.7, 75.3, 80.5, 73.0, 77.0, 77.5, 69.2, 60.0, 78.2, 79.5, 61.8, 49.6, 59.6, 72.1, 71.0, 76.3, 72.8, 71.8, 60.7, 67.0, 71.8, 71.2, 68.3, 68.5, 54.8, 76.0, 65.8, 69.4, 66.9, 69.7, 71.2, 59.6])
y = np.array([41.4, 76.3, 59.2, 51.8, 52.5, 53.2, 62.4, 55.0, 57.7, 63.2, 37.5, 48.5, 32.4, 20.5, 47.9, 68.0, 68.5, 52.5, 63.3, 58.8, 59.7, 48.4, 40.7, 51.0, 50.9, 34.3, 25.8, 32.1, 34.4, 55.1, 60.3, 57.0, 45.6, 54.2, 55.1, 55.7, 70.3, 61.8, 47.6, 42.5, 71.3, 55.2, 65.2, 42.9, 54.7, 62.0, 48.2])

r = np.sum((x-np.mean(x))*(y-np.mean(y)))/(np.sqrt(np.sum((x-np.mean(x))**2))*np.sqrt(np.sum((y-np.mean(y))**2)))

print("correlation coef: {:.3f}".format(r))

・実行結果

> print("correlation coef: {:.3f}".format(r))
correlation coef: 0.637

問題3.2の解答例

問題3.3の解答例

下記を実行することで、スピアマンの順位相関係数とケンドールの順位相関係数に基づく相関行列を作成することができる。

import numpy as np

x = np.array([[1., 1., 8., 20.], [2., 5., 3., 1.], [3., 2., 1., 4.], [4., 3., 4., 2.], [5., 6., 2., 6.], [6., 7., 5., 3.], [7., 15., 11., 12.], [8., 8., 7., 17.], [9., 4., 15., 8.], [10., 11., 9., 5.], [11., 10., 6., 18], [12., 14., 13., 13.], [13., 18., 10., 23.], [14., 13., 22., 26.], [15., 22., 12., 29.], [16., 24., 14., 15.], [17., 16., 18., 16.], [18., 19., 19., 9.], [19., 30., 17., 10.], [20., 9., 22., 11.], [21., 25., 16., 30.], [22., 17., 24., 7.], [23., 26., 21., 27.], [24., 23., 20., 19.], [25., 12., 28., 14.], [26., 20., 30., 21.], [27., 28., 25., 28.], [28., 21., 26., 24.], [29., 27., 27., 22.], [30., 29., 29., 25]])

cor_mat_spearman = np.zeros([x.shape[1],x.shape[1]])
cor_mat_kendall = np.zeros([x.shape[1],x.shape[1]])

for i in range(x.shape[1]):
    for j in range(x.shape[1]):
        cor_mat_spearman[i,j] = 1. - 6.*np.sum((x[:,i]-x[:,j])**2)/(x.shape[0]*(x.shape[0]**2-1))
        P, N = 0., 0.
        for k in range(x.shape[0]):
            for l in range(k+1,x.shape[0]):
                if (x[k,i]-x[l,i])*(x[k,j]-x[l,j])>=0:
                    P += 1.
                else:
                    N += 1.
        cor_mat_kendall[i,j] = 2*(P-N)/(x.shape[0]*(x.shape[0]-1.))

print("・Spearman Correlation:")
print(cor_mat_spearman)
print("・Kendall Correlation:")
print(cor_mat_kendall)

・実行結果

・Spearman Correlation:
[[ 1.          0.82157953  0.9272525   0.59332592]
 [ 0.82157953  1.          0.67185762  0.63737486]
 [ 0.9272525   0.67185762  1.          0.53437152]
 [ 0.59332592  0.63737486  0.53437152  1.        ]]
・Kendall Correlation:
[[ 1.          0.66436782  0.77011494  0.43908046]
 [ 0.66436782  1.          0.50344828  0.46206897]
 [ 0.77011494  0.50344828  1.          0.36091954]
 [ 0.43908046  0.46206897  0.36091954  1.        ]]

問題3.4の解答例

i)
巻末の解答では一様乱数が得られる前提なので、以下、numpy.random.randを用いて一様乱数は得られる前提で考える。なお、一様乱数が得られない場合は、乗算合同法などを用いればよい。

下記を実行することで[1, 11]に属する整数の乱数を生成することができる。

import numpy as np

np.random.seed(0)

rand_x = np.random.rand(100)
rand_x_int = np.zeros(100)
for i in range(11):
    rand_x_int[rand_x>i/11.] = i+1

print(rand_x_int)

・実行結果

[  7.   8.   7.   6.   5.   8.   5.  10.  11.   5.   9.   6.   7.  11.   1.
   1.   1.  10.   9.  10.  11.   9.   6.   9.   2.   8.   2.  11.   6.   5.
   3.   9.   6.   7.   1.   7.   7.   7.  11.   8.   4.   5.   8.   1.   8.
   8.   3.   2.   4.   5.   7.   5.  11.   2.   3.   2.   8.   3.   6.   3.
   2.   2.   8.   2.   3.   5.  10.   2.  10.   2.  11.   6.  11.   7.   9.
   1.   4.   2.   4.   2.   4.   5.   1.   8.   7.   3.   6.   2.   7.  11.
   4.   8.   2.   8.   4.   3.   7.   1.  10.   1.]

ⅱ)
下記を実行することで相関係数の計算を行うことができる。

import numpy as np

np.random.seed(0)

x = np.array([71., 68., 66., 67., 70., 71., 70., 73., 72., 65., 66.])
y = np.array([69., 64., 65., 63., 65., 62., 65., 64., 66., 59., 62.])
x_, y_ = np.zeros(11), np.zeros(11)

rand_idx = np.random.rand(11)
rand_idx_int = np.zeros(11)
for i in range(11):
    rand_idx_int[rand_idx>i/11.] = i+1

for i in range(11):
    x_[i] = x[rand_idx_int[i]-1]
    y_[i] = y[rand_idx_int[i]-1]

r = np.sum((x_-np.mean(x_))*(y_-np.mean(y_)))/np.sqrt(np.sum((x_-np.mean(x_))**2) * np.sum((y_-np.mean(y_))**2))

print("Correlation coef: {:.3f}".format(r))

・実行結果

> print("Correlation coef: {:.3f}".format(r))
Correlation coef: 0.678

ⅲ)
ブートストラップ法に基づくヒストグラムは下記を実行することで作成できる。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)

x = np.array([71., 68., 66., 67., 70., 71., 70., 73., 72., 65., 66.])
y = np.array([69., 64., 65., 63., 65., 62., 65., 64., 66., 59., 62.])
x_, y_ = np.zeros(11), np.zeros(11)

r = np.zeros(200)

for i in range(r.shape[0]):
    rand_idx = np.random.rand(11)
    rand_idx_int = np.zeros(11)

    for j in range(11):
        rand_idx_int[rand_idx>j/11.] = j+1

    for j in range(11):
        x_[j] = x[rand_idx_int[j]-1]
        y_[j] = y[rand_idx_int[j]-1]
    r[i] = np.sum((x_-np.mean(x_))*(y_-np.mean(y_)))/np.sqrt(np.sum((x_-np.mean(x_))**2) * np.sum((y_-np.mean(y_))**2))

plt.hist(r, color="lightblue")
plt.show()

・実行結果

まとめ

Pythonを用いたノンパラメトリック法のプログラミング 〜順位和検定、符号検定 etc〜

数式だけの解説ではわかりにくい場合もあると思われるので、統計学の手法や関連する概念をPythonのプログラミングで表現します。当記事ではノンパラメトリック法の理解にあたって、順位和検定、並べ替え検定、符号検定などのPythonでの実装を取り扱いました。

・Pythonを用いた統計学のプログラミングまとめ
https://www.hello-statisticians.com/stat_program

ノンパラメトリック法まとめ

Pythonを用いた処理

順位和検定

順位和検定は、2つの群$A,B$に関してそれぞれ観測値が得られるとき、観測値を小さい順に並べ、$A$の順位和の$P$値を計算する手法である。計算にあたっては組み合わせの計算を主に行う。処理の一連の流れは下記のようにPythonを用いて表すことができる。

・順位和の計算

import numpy as np

x = np.array([5., 10., 15., 12., 16., 20.])
x_A = x[:3]
x_B = x[3:]

rank_A, rank_B = np.argsort(x)[:3]+1, np.argsort(x)[3:]+1
sum_rank_A, sum_rank_B = np.sum(rank_A), np.sum(rank_B)

print("(x_A, x_B): ({}, {})".format(x_A, x_B))
print("(rank_A, rank_B): ({}, {})".format(rank_A, rank_B))
print("(sum_rank_A, sum_rank_B): ({}, {})".format(sum_rank_A, sum_rank_B))

・実行結果

> print("(x_A, x_B): ({}, {})".format(x_A, x_B))
(x_A, x_B): ([  5.  10.  15.], [ 12.  16.  20.])
> print("(rank_A, rank_B): ({}, {})".format(rank_A, rank_B))
(rank_A, rank_B): ([1 2 4], [3 5 6])
> print("(sum_rank_A, sum_rank_B): ({}, {})".format(sum_rank_A, sum_rank_B))
(sum_rank_A, sum_rank_B): (7, 14)

・$P$値の計算

x = np.array([5., 10., 15., 12., 16., 20.])
x_A = x[:3]
x_B = x[3:]

rank_x = np.argsort(x)+1
rank_A, rank_B = rank_x[:3], rank_x[3:]
sum_rank_A, sum_rank_B = np.sum(rank_A), np.sum(rank_B)

count_A, count_all = 0., 0.
for i in range(x.shape[0]-2):
    for j in range(i+1,x.shape[0]-1):
       for k in range(j+1,x.shape[0]):
           count_all += 1.
           if (rank_x[i]+rank_x[j]+rank_x[k]) <= sum_rank_A:
               count_A += 1.

print("P-value: {}/{}={}".format(int(count_A), int(count_all), count_A/count_all))

・実行結果

> print("P-value: {}/{}={}".format(int(count_A), int(count_all), count_A/count_all))
P-value: 2/20=0.1

並べ替え検定

下記で取り扱いを行った。
https://www.hello-statisticians.com/explain-books-cat/stat_workbook/stat_workbook_ch13.html#132

符号付き順位検定

符号検定

符号検定(sign test)は$n$個の観測値に関して値が正の観測値の数を$T_{+}$のように数え、この個数が二項分布$Bin(n,0.5)$に従うことに基づいて行う検定である。以下、$n=10$の場合で考える。

・二項分布$Bin(10,0.5)$の描画

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

def calc_combination_vec(n, vec):
    res = np.zeros(11)
    for i in range(vec.shape[0]):
        res[i] = math.factorial(n) / (math.factorial(vec[i]) * math.factorial(n-vec[i]))
    return res

x = np.arange(0.,11.,1.)
p = calc_combination_vec(10, x) * 0.5**10

plt.bar(x, p, color="lightblue")
plt.show()

・実行結果

・$P$値の計算

x = np.arange(0.,11.,1.)
T = np.array([8., 9., 10.])
p = calc_combination_vec(10, x) * 0.5**10

p_value = np.array([np.sum(p[8:]), np.sum(p[9:]), np.sum(p[10:])])
print("P_value: {}".format(p_value))

・実行結果

> print("P_value: {}".format(p_value))
P_value: [ 0.0546875   0.01074219  0.00097656]

クラスカル・ウォリス検定

下記で取り扱いを行った。
https://www.hello-statisticians.com/explain-books-cat/stat_workbook/stat_workbook_ch13.html#134

「統計学実践ワークブック」 演習問題etc Ch.29 「不完全データの統計処理」

当記事は「統計学実践ワークブック(学術図書出版社)」の読解サポートにあたってChapter.29の「不完全データの統計処理」に関して演習問題を中心に解説を行います。欠損値の取り扱いは実際によく出てくる課題であるので、演習などを通して一通りの手法を確認しておくと良いと思われました。

本章のまとめ

欠測メカニズム

欠測が生じる原理は主にMCAR(Missing Completely At Random)、MAR(Missing Completely Random)、MNAR(Missing Not At Random)の3通りに分類される。$(x,y)$が観測されるとき、$y$の欠測はそれぞれ下記のように考えることができる。

・MCAR
-> yの欠測は完全にランダムに生じる。平均、標準偏差、相関係数、回帰の際の係数は欠測が生じなかった場合に概ね一致する。

・MAR
-> yの欠測はxの値に基づいて生じる。xとyに相関がある場合、回帰係数は概ね同じ一方で$y$の平均や標準偏差には変化が生じる場合がある。

・MNAR
-> yの欠測はyの値に基づいて生じる。xとyに相関がある場合、回帰係数やyの平均や標準偏差に変化が生じる場合がある。

削除法・代入法

削除法(deletion method)は「欠測のある個体に対応する行を削除する手法」である。削除法はCC(Complete Case)解析とAC(Available Case)解析に分けられ、CC解析では欠測がある行を全て取り除く一方で、AC解析では使える値は全て用いて計算を行う。

欠測数があまり多くない場合や分散共分散行列を計算する場合はCC解析が妥当である一方で、変量数と欠測が多い場合はAC解析の方が妥当である。

補間法・代入法(imputation method)は「欠測箇所に何らかの値を代入する手法」である。主に下記の手法が用いられる。

i) 平均値代入
-> 着目する変数の観測値の平均値を代入する

ⅱ) 回帰代入
-> 回帰式によって欠測部分を予測する

ⅲ) Hot Dech法
-> 欠測のある個体と類似の個体を探し、その観測値を欠測部分に代入する

演習問題解説

例29.1

下記を実行することで、打ち切りとトランケートされた場合の二つの場合の最尤推定値を計算できる。

import numpy as np
from scipy import stats

x_all = np.array([35., 38., 42., 45., 49., 52., 53., 56., 63., 65.])
x_observed = np.array([35., 38., 42., 45., 49., 52., 53., 56.])

c = 60.
sigma = 10.
mean_x_all = np.mean(x_all)
mean_x_observed = np.mean(x_observed)

mean_mle_censoring = np.mean(x_observed)
mean_mle_truncate = np.mean(x_observed)
for i in range(10):
    a1 = (c-mean_mle_censoring)/sigma
    mean_mle_censoring = (np.sum(x_observed)+(x_all.shape[0]-x_observed.shape[0])*(mean_mle_censoring+(stats.norm.pdf(a1)*sigma)/(1-stats.norm.cdf(a1))))/x_all.shape[0]
    a2 = (c-mean_mle_truncate)/sigma
    mean_mle_truncate = mean_x_observed + (stats.norm.pdf(a2)/stats.norm.cdf(a2))*sigma

print("Result_Censoring: {}".format(mean_mle_censoring))
print("Result_Truncate: {}".format(mean_mle_truncate))

・実行結果

> print("Result_Censoring: {}".format(mean_mle_censoring))
Result_Censoring: 50.0523586591
> print("Result_Truncate: {}".format(mean_mle_truncate))
Result_Truncate: 48.6544391675

どちらの結果からも標本平均が実際の平均よりも小さいことを改善していることが確認できる。

例29.2

下記を実行することで、$(29.5)$式〜$(29.8)$式の値の計算を行うことができる。

・$(29.5)$式

import numpy as np

x = np.array([35., 37., 40., 45., 47., 54., 57., 60., 62., 63])

print("mu_x: {:.1f}".format(np.mean(x)))
print("sigma_x^2: {:.1f}".format(np.sum((x-np.mean(x))**2)/x.shape[0]))

・実行結果

mu_x: 50.0
sigma_x^2: 100.6

・$(29.6)$式

import numpy as np

x = np.array([35., 37., 40., 45., 47., 54., 57.])
y = np.array([40., 38., 48., 41., 60., 46., 57.])

print("Mean x: {:.1f}".format(np.mean(x)))
print("s_x^2: {:.2f}".format(np.sum((x-np.mean(x))**2)/x.shape[0]))
print("Mean y: {:.2f}".format(np.mean(y)))
print("s_y^2: {:.2f}".format(np.sum((y-np.mean(y))**2)/y.shape[0]))
print("r: {:.2f}".format(np.sum((x-np.mean(x))*(y-np.mean(y)))/np.sqrt(np.sum((x-np.mean(x))**2)*np.sum((y-np.mean(y))**2))))

・実行結果

Mean x: 45.0
s_x^2: 59.71
Mean y: 47.14
s_y^2: 62.41
r: 0.64

・$(29.7)$式

import numpy as np

x = np.array([35., 37., 40., 45., 47., 54., 57.])
y = np.array([40., 38., 48., 41., 60., 46., 57.])

s_xy = np.sum((x-np.mean(x))*(y-np.mean(y)))/x.shape[0]
s_x2 = np.sum((x-np.mean(x))**2)/x.shape[0]
s_y2 = np.sum((y-np.mean(y))**2)/y.shape[0]

beta = s_xy/s_x2
alpha = np.mean(y)-beta*np.mean(x)
tau2 = s_y2 - s_xy**2/s_x2

print("alpha: {:.2f}".format(alpha))
print("beta: {:.2f}".format(beta))
print("tau^2: {:.2f}".format(tau2))

・実行結果

alpha: 17.65
beta: 0.66
tau^2: 36.75

・$(29.8)$式

import numpy as np

x_all = np.array([35., 37., 40., 45., 47., 54., 57., 60., 62., 63])
x = np.array([35., 37., 40., 45., 47., 54., 57.])
y = np.array([40., 38., 48., 41., 60., 46., 57.])

sigma_x2 = np.sum((x_all-np.mean(x_all))**2)/x_all.shape[0]

s_xy = np.sum((x-np.mean(x))*(y-np.mean(y)))/x.shape[0]
s_x2 = np.sum((x-np.mean(x))**2)/x.shape[0]
s_y2 = np.sum((y-np.mean(y))**2)/y.shape[0]

beta = s_xy/s_x2
alpha = np.mean(y)-beta*np.mean(x)
tau2 = s_y2 - s_xy**2/s_x2

print("mu_y: {:.2f}".format(alpha+beta*np.mean(x_all)))
print("sigma_y: {:.2f}".format(tau2+beta**2*sigma_x2))
print("sigma_xy: {:.2f}".format(beta*sigma_x2))
print("rho: {:.2f}".format(beta*sigma_x2/np.sqrt(sigma_x2*(tau2+beta**2*sigma_x2))))

・実行結果

mu_y: 50.42
sigma_y: 79.98
sigma_xy: 65.94
rho: 0.74

$(29.8)$式の結果の計算にあたって有効数字の取り扱いを行わなかったことで、ワークブックの解答と少々異なる結果が得られた。

問29.1

$[1]$

$2$回の試験の間の相関係数が正であり、$1$回目の試験の合否で$2$回目の試験を受験するかが決まることから、$2$回目の試験結果が良いと思われる生徒が$2$回目の試験を受験していないと考えることができる。

よって、$\bar{y}_B$は$\mu_Y$を過小評価し、同様に$r_{B}$は$\rho$を過小評価すると考えられる。

$[2]$

標本平均には偏りがないが、回帰による予測値が回帰直線に一致することから相関係数を過大に評価すると考えることができる。

参考

・準1級関連まとめ
https://www.hello-statisticians.com/toukeikentei-semi1

Ch.1 「時系列分析の基礎概念」の章末問題の解答例 〜計量時系列分析 朝倉書店〜

当記事は「経済・ファイナンスデータの計量時系列分析(朝倉書店)」の読解サポートにあたってChapter.1の「時系列分析の基礎概念」の章末問題の解説について行います。

基本的には書籍の購入者向けの解答例・解説なので、まだ入手されていない方は入手の上、ご確認ください。また、解説はあくまでサイト運営者が独自に作成したものであり、書籍の公式ページではないことにご注意ください。(そのため著者の意図とは異なる解説となる可能性はあります)

また、下記に公式の解答があるので、こちらも合わせて参照ください。
https://www.asakura.co.jp/user_data/contents/12792/3.pdf

章末の演習問題について

問題1.1の解答例

ラグ$k$の自己共分散$\gamma_{k}$に関して下記が成立する。
$$
\large
\begin{align}
\gamma_{k} = Cov(y_t, y_{t-k}) = Cov(y_{t-k}, y_t) = \gamma_{-k}
\end{align}
$$

上記より、$\gamma_{k}=\gamma_{-k}$が成立することが確認できる。

問題1.2の解答例

$$
\large
\begin{align}
y_{t} = \mu + \epsilon_{t}, \quad \epsilon_{t} \sim W.N.(\sigma^2)
\end{align}
$$

上記で表した$(1.8)$式の確率過程の平均$E[Y_t]$、分散$V[Y_t]$、自己共分散$Cov[Y_t,Y_{t-k}]$はそれぞれ下記のように表すことができる。
$$
\large
\begin{align}
E[Y_t] &= E[\mu + \epsilon_{t}] = \mu \\
V[Y_t] &= V[\mu + \epsilon_{t}] \\
&= V[\epsilon_{t}] = \sigma^2 \\
Cov[Y_t,Y_{t-k}] &= Cov[\mu + \epsilon_{t},\mu + \epsilon_{t-k}] \\
&= Cov[\epsilon_{t},\epsilon_{t-k}] = 0
\end{align}
$$

上記より、式$(1.8)$は定常過程と考えることができる。

問題1.3の解答例

下記を実行することで図$1.3$と同様の結果が得られる。

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

np.random.seed(0)

mu = np.array([0., 2., -2., 0., 0., 2.])
sigma = np.array([1., 1., 1., 2., 3., 2.])
x = np.arange(0,100,1)
y = np.zeros([x.shape[0],mu.shape[0]])

for i in range(x.shape[0]):
    y[i,:] = mu + stats.norm.rvs(0,sigma,size=6)

for i in range(6):
    plt.subplot(2,3,i+1)
    plt.plot(x,y[:,i])
    plt.title("mu={}, sigma={}".format(mu[i],sigma[i]))

plt.legend()
plt.show()

・実行結果

問題1.4の解答例

平均と分散が等しいいくつかの分布を用意し、$t$に関して何らかの規則に基づいて$y_t$が異なる分布に基づいて生成されるようにすることで、$y_t$は弱定常過程にはなるが強定常過程にはならない。

問題1.5の解答例

「統計学実践ワークブック」 演習問題etc Ch.27 「時系列解析」

当記事は「統計学実践ワークブック(学術図書出版社)」の読解サポートにあたってChapter.27の「時系列解析」に関して演習問題を中心に解説を行います。AR過程、MA過程、ARMA過程や、ホワイトノイズ、コレログラムなど、よく用いられる内容が多いので、抑えておくと良いと思われました。

本章のまとめ

下記などで取り扱いを行った。
https://www.hello-statisticians.com/python/stat_program3.html

演習問題解説

問27.1

$[1]$
対応は下記のようになる。

a) -> 0.7
b) -> 0
c) -> 1
d) -> -0.8

$\phi_1$の値が大きくなるにつれて前後の値が相関することから、グラフの動きがなだらかになる。

また、$AR(1)$過程$y_t = c + \phi_1 y_{t-1} + u_t$の期待値が$\displaystyle E[Y_t]=\frac{c}{1-\phi_1}$となることから、$\phi_1 \neq 0$のときは$c=1-\phi_1$より$\displaystyle E[Y_t]=2$が成立することも抑えておくとよい。

$[2]$

誤差項に自己相関がある場合も、最小二乗法は不偏推定量であるが、有効な推定量ではない。また、正の自己相関がある場合、$DW$比は$0$に近い値を取る。

問27.2

$h=0,1,2$次の自己共分散は下記のように計算できる。
$$
\large
\begin{align}
\gamma_0 &= E[(Y_t-E[Y_t])^2] = E[(Y_t)^2] \\
&= E[(U_t + \theta_1 U_{t-1} \theta_2 U_{t-2})^2] \\
&= E[U_t^{2}] + \theta_1^2 E[U_{t-1}^{2}] + \theta_2^2 E[U_{t-2}^2] = (1+\theta_1^2+\theta_2^2)\sigma^2 \\
\gamma_1 &= E[(Y_t-E[Y_t])(Y_{t-1}-E[Y_{t-1}])] = E[Y_tY_{t-1}] \\
&= E[(U_t + \theta_1 U_{t-1} + \theta_2 U_{t-2})(U_{t-1} + \theta_1 U_{t-2} + \theta_2 U_{t-3})] \\
&= \theta_1 E[U_{t-1}^{2}] + \theta_1 \theta_2 E[U_{t-2}^2] = (\theta_1 + \theta_1 \theta_2)\sigma^2 \\
\gamma_2 &= E[(Y_t-E[Y_t])(Y_{t-2}-E[Y_{t-2}])] = E[Y_tY_{t-2}] \\
&= E[(U_t + \theta_1 U_{t-1} + \theta_2 U_{t-2})(U_{t-2} + \theta_1 U_{t-3} + \theta_2 U_{t-4})] \\
&= \theta_2 E[U_{t-2}^{2}] = \theta_2 \sigma^2
\end{align}
$$

$h>2$次の自己共分散は下記のように計算できる。
$$
\large
\begin{align}
\gamma_h &= E[(Y_t-E[Y_t])(Y_{t-h}-E[Y_{t-h}])] = E[Y_tY_{t-h}] \\
&= E[(U_t + \theta_1 U_{t-1} + \theta_2 U_{t-2})(U_{t-h} + \theta_1 U_{t-h-1} + \theta_2 U_{t-h-2})] \\
&= 0
\end{align}
$$

問27.3

$[1]$
$AR(p)$過程の$p+1$次以上の偏自己相関係数は全て$0$となるが、ここでは$3$次以上の標本偏自己相関係数に$0$に近い値が確認される。よって、$AR(2)$を元に考えると良いことがわかる。

$[2]$
$DW$比の近似値は下記のように考えることができる。
$$
\large
\begin{align}
DW & \simeq 2(1-\hat{\gamma}_1) \\
&= 2(1-0.691) = 0.618
\end{align}
$$

問27.4

AICが最も小さいものを考えれば良いので$AR(3)$を選べば良い。

参考

・準1級関連まとめ
https://www.hello-statisticians.com/toukeikentei-semi1

・Pythonを用いた時系列解析のプログラミング
https://www.hello-statisticians.com/python/stat_program3.html

Pythonを用いた時系列解析のプログラミング 〜AR過程、MA過程、コレログラム etc〜

数式だけの解説ではわかりにくい場合もあると思われるので、統計学の手法や関連する概念をPythonのプログラミングで表現します。当記事では時系列解析(Time-series Analysis)の理解にあたって、AR過程、MA過程、コレログラムなどのPythonでの実装を取り扱いました。

・Pythonを用いた統計学のプログラミングまとめ
https://www.hello-statisticians.com/stat_program

ARMA過程・共分散定常

AR過程

$$
\large
\begin{align}
y_t = c + \phi_1 y_{t-1} + u_t \quad (1)
\end{align}
$$
系列$\{y_t\}$を上記のような$AR(1)$過程を元に表現することを考える。ここで系列$\{u_t\}$には平均$0$、分散$\sigma^2$のホワイトノイズを考える。以下、ここで定義した式を元に$AR(1)$過程の生成と、期待値・自己共分散の計算に関して取り扱う。

AR過程の生成

式$(1)$に対し、$c=5$、$\phi_1=\{0, 0.5, 0.7\}$、$y_0=2$、ホワイトノイズの分散を$\sigma^2=1$と設定するとき、下記のように$AR(1)$過程の生成を行うことができる。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(0)

c = 5.
phi = np.array([0, 0.5, 0.7])
x = np.arange(0., 100., 1.)
y = np.zeros([100,3])
y[0,:] = 2*np.ones(3)

for i in range(1, y.shape[0]):
     y[i, :] = c + phi*y[i-1, :] + stats.norm.rvs(0,size=3)

for i in range(3):
    plt.plot(x, y[:,i])

plt.show()

・実行結果

上記はどれも$\phi_1$に関して生成を行ったので、$\phi_1=-0.7$に関しても確認を行う。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(0)

c = 5.
phi = np.array([-0.7])
x = np.arange(0., 100., 1.)
y = np.zeros([100,1])
y[0,:] = 2*np.ones(1)

for i in range(1, y.shape[0]):
     y[i, :] = c + phi*y[i-1, :] + stats.norm.rvs(0,size=1)

for i in range(1):
    plt.plot(x, y[:,i])

plt.show()

・実行結果

$\phi_1$の値が負の場合、$y_t-\bar{y}$と$y_{t-1}-\bar{y}$が異符号になりやすいことを意味するので、$\phi_1 \geq 0$のときに比べて値の上下がしやすくなることに注意しておくと良い。

AR過程の期待値、自己共分散

・期待値の計算

$$
\large
\begin{align}
E[Y_t] = \frac{c}{1-\phi_1} \quad (2)
\end{align}
$$
$(1)$式で定義を行った$AR(1)$過程は、$|\phi_1|<1$のとき、上記のような期待値を考えることができる。ここでは$Y_t$と$y_t$は確率変数とその実現値のように表記を使い分けた。

以下、前項で生成した系列の平均が$(2)$式に一致するかの確認を行う。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(0)

c = 5.
phi = np.array([-0.7, 0, 0.3, 0.5, 0.7])
y = np.zeros([110,5])
y[0,:] = 2*np.ones(5)

for i in range(1, y.shape[0]):
     y[i, :] = c + phi*y[i-1, :] + stats.norm.rvs(0,size=5)

print(np.mean(y[:10,:],axis=0))
print(np.mean(y[10:,:],axis=0))
print(c/(1.-phi))

・実行結果

> print(np.mean(y[:10,:],axis=0))
[  2.63929888   5.21864106   6.56471946   8.84802352  13.34988176]
> print(np.mean(y[10:,:],axis=0))
[  2.88815475   4.9228795    7.04124409   9.65664408  17.04847973]
> print(c/(1.-phi))
[  2.94117647   5.           7.14285714  10.          16.66666667]

実行結果を確認すると、$(2)$式が概ね正しいことが確認できる。また、$110$個の値を生成し、$1$つ目から$100$個と、$11$個目の$100$個を元に平均の比較を行った。これにより初期値により依存しない定常状態での計算が行うことができ、実行結果からもそのことを反映していることが確認できる。

・分散、1次の自己共分散の計算
$$
\large
\begin{align}
\gamma_{0} &= \frac{\sigma^2}{1-\phi_{1}^{2}} \quad (3) \\
\gamma_{1} &= \phi_{1} \frac{\sigma^2}{1-\phi_{1}^{2}} \quad (4)
\end{align}
$$
$(1)$式で定義を行った$AR(1)$過程は、$|\phi_1|<1$のとき、上記のような分散$\gamma_{0}$と1次の自己共分散$\gamma_{1}$を考えることができる。ここでは$Y_t$と$y_t$は確率変数とその実現値のように表記を使い分けた。

以下、前項で生成した系列の分散と1次の自己共分散が$(3), (4)$式に一致するかの確認を行う。

np.random.seed(0)

c = 5.
phi = np.array([-0.7, 0, 0.3, 0.5, 0.7])
y = np.zeros([110,5])
y[0,:] = 2*np.ones(5)

for i in range(1, y.shape[0]):
     y[i, :] = c + phi*y[i-1, :] + stats.norm.rvs(0,size=5)

y_t = y[10:,:]
y_t_1 = y[9:109,:]
est_gamma_0 = np.sum((y_t-np.mean(y_t,axis=0))**2, axis=0)/y_t.shape[0]
est_gamma_1 = np.sum((y_t-np.mean(y_t,axis=0))*(y_t_1-np.mean(y_t_1,axis=0)), axis=0)/y_t.shape[0]
pop_gamma_0 = 1./(1.-phi**2)
pop_gamma_1 = phi*1./(1.-phi**2)

print("population gamma_0: {}".format(pop_gamma_0))
print("estimated gamma_0: {}".format(est_gamma_0))
print("===")
print("population gamma_1: {}".format(pop_gamma_1))
print("estimated gamma_1: {}".format(est_gamma_1))

・実行結果

population gamma_0: [ 1.96078431  1.          1.0989011   1.33333333  1.96078431]
estimated gamma_0: [ 1.96412646  0.89642751  1.17330429  1.63729046  1.53448253]
===
population gamma_1: [-1.37254902  0.          0.32967033  0.66666667  1.37254902]
estimated gamma_1: [-1.41202877  0.00415049  0.37561853  1.01843126  0.9910005 ]

以下生成するyの要素の数を増やして同様の確認を行う。

np.random.seed(0)

c = 5.
phi = np.array([-0.7, 0, 0.3, 0.5, 0.7])
y = np.zeros([10100,5])
y[0,:] = 2*np.ones(5)

for i in range(1, y.shape[0]):
     y[i, :] = c + phi*y[i-1, :] + stats.norm.rvs(0,size=5)

y_t = y[100:,:]
y_t_1 = y[99:10099,:]
est_gamma_0 = np.sum((y_t-np.mean(y_t,axis=0))**2, axis=0)/y_t.shape[0]
est_gamma_1 = np.sum((y_t-np.mean(y_t,axis=0))*(y_t_1-np.mean(y_t_1,axis=0)), axis=0)/y_t.shape[0]
pop_gamma_0 = 1./(1.-phi**2)
pop_gamma_1 = phi*1./(1.-phi**2)

print("population gamma_0: {}".format(pop_gamma_0))
print("estimated gamma_0: {}".format(est_gamma_0))
print("===")
print("population gamma_1: {}".format(pop_gamma_1))
print("estimated gamma_1: {}".format(est_gamma_1))

・実行結果

population gamma_0: [ 1.96078431  1.          1.0989011   1.33333333  1.96078431]
estimated gamma_0: [ 1.97233741  1.0029984   1.0905944   1.32661458  1.97339705]
===
population gamma_1: [-1.37254902  0.          0.32967033  0.66666667  1.37254902]
estimated gamma_1: [-1.38088791  0.01162902  0.32819272  0.66243822  1.40465808]

MA過程

$$
\large
\begin{align}
y_t = \mu + u_t + \theta_{1} u_{t-1} \quad (5)
\end{align}
$$
系列${y_t}$を上記のような$MA(1)$過程を元に表現することを考える。ここで系列${u_t}$には平均$0$、分散$\sigma^2$のホワイトノイズを考える。以下、ここで定義した式を元に$MA(1)$過程の生成と、期待値・自己共分散の計算に関して取り扱う。

MA過程の生成

式$(5)$に対し、$\mu=2$、$\phi_1=\{-0.9, 0, 2.5\}$、ホワイトノイズの分散を$\sigma^2=1$と設定するとき、下記のように$MA(1)$過程の生成を行うことができる。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(0)

mu = 2
theta = np.array([-0.9, 0., 2.5])
x = np.arange(0., 100., 1.)
y = np.zeros([100,3])

u_t_1 = stats.norm.rvs(0,size=3)
for i in range(y.shape[0]):
    u_t = stats.norm.rvs(0,size=3)
    y[i, :] = mu + u_t + theta*u_t_1
    u_t_1 = u_t

for i in range(3):
    plt.plot(x, y[:,i],label="theta:{}".format(theta[i]))

plt.legend()
plt.show()

・実行結果

MA過程の期待値、自己共分散

・期待値の計算

$$
\large
\begin{align}
E[Y_t] = \mu \quad (6)
\end{align}
$$
$(5)$式で定義を行った$MA(1)$過程は、上記のような期待値を考えることができる。ここでは$Y_t$と$y_t$は確率変数とその実現値のように表記を使い分けた。

以下、前項で生成した系列の平均が$(6)$式に一致するかの確認を行う。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(0)

mu = 2
theta = np.array([-0.9, 0., 2.5])
y = np.zeros([100,3])

u_t_1 = stats.norm.rvs(0,size=3)
for i in range(y.shape[0]):
    u_t = stats.norm.rvs(0,size=3)
    y[i, :] = mu + u_t + theta*u_t_1
    u_t_1 = u_t

print(np.mean(y,axis=0))
print(mu)

・実行結果

> print(np.mean(y,axis=0))
[ 1.97934626  2.11883204  1.55438665]
> print(mu)
2

・分散、1次の自己共分散の計算

$$
\large
\begin{align}
\gamma_{0} &= (1+\theta_{1}^{2}) \sigma^2 \quad (7) \\
\gamma_{1} &= \theta_1 \sigma^2 \quad (8)
\end{align}
$$
$(5)$式で定義を行った$AR(1)$過程は、上記のような分散$\gamma_{0}$と1次の自己共分散$\gamma_{1}$を考えることができる。ここでは$Y_t$と$y_t$は確率変数とその実現値のように表記を使い分けた。

以下、前項で生成した系列の分散と1次の自己共分散が$(7), (8)$式に一致するかの確認を行う。

np.random.seed(0)

mu = 2
theta = np.array([-0.9, 0., 2.5])
y = np.zeros([101,3])

u_t_1 = stats.norm.rvs(0,size=3)
for i in range(y.shape[0]):
    u_t = stats.norm.rvs(0,size=3)
    y[i, :] = mu + u_t + theta*u_t_1
    u_t_1 = u_t

y_t = y[1:,:]
y_t_1 = y[:-1,:]
est_gamma_0 = np.sum((y_t-np.mean(y_t,axis=0))**2, axis=0)/y_t.shape[0]
est_gamma_1 = np.sum((y_t-np.mean(y_t,axis=0))*(y_t_1-np.mean(y_t_1,axis=0)), axis=0)/y_t.shape[0]
pop_gamma_0 = 1.+theta**2
pop_gamma_1 = theta

print("population gamma_0: {}".format(pop_gamma_0))
print("estimated gamma_0: {}".format(est_gamma_0))
print("===")
print("population gamma_1: {}".format(pop_gamma_1))
print("estimated gamma_1: {}".format(est_gamma_1))

・実行結果

population gamma_0: [ 1.81  1.    7.25]
estimated gamma_0: [ 1.5933599   0.95971088  7.29452229]
===
population gamma_1: [-0.9  0.   2.5]
estimated gamma_1: [-0.75201479 -0.13068008  2.62407484]

以下生成するyの要素の数を増やして同様の確認を行う。

np.random.seed(0)

mu = 2
theta = np.array([-0.9, 0., 2.5])
y = np.zeros([10100,3])

u_t_1 = stats.norm.rvs(0,size=3)
for i in range(y.shape[0]):
    u_t = stats.norm.rvs(0,size=3)
    y[i, :] = mu + u_t + theta*u_t_1
    u_t_1 = u_t

y_t = y[100:,:]
y_t_1 = y[99:10099,:]
est_gamma_0 = np.sum((y_t-np.mean(y_t,axis=0))**2, axis=0)/y_t.shape[0]
est_gamma_1 = np.sum((y_t-np.mean(y_t,axis=0))*(y_t_1-np.mean(y_t_1,axis=0)), axis=0)/y_t.shape[0]
pop_gamma_0 = 1.+theta**2
pop_gamma_1 = theta

print("population gamma_0: {}".format(pop_gamma_0))
print("estimated gamma_0: {}".format(est_gamma_0))
print("===")
print("population gamma_1: {}".format(pop_gamma_1))
print("estimated gamma_1: {}".format(est_gamma_1))

・実行結果

population gamma_0: [ 1.81  1.    7.25]
estimated gamma_0: [ 1.82644804  0.9895947   7.04606486]
===
population gamma_1: [-0.9  0.   2.5]
estimated gamma_1: [ -9.48202031e-01   2.08049843e-03   2.39463923e+00]

共分散定常

コレログラム

AR過程のコレログラム

$$
\large
\begin{align}
y_t = c + \phi_1 y_{t-1} + u_t \quad (1)
\end{align}
$$

前節で取り扱った上記のように表される$AR$過程の$h$次の自己共分散は下記のように表される。
$$
\large
\begin{align}
\gamma_{h} &= \phi_{1}^{h} \frac{\sigma^2}{1-\phi_{1}^{2}} \quad (9)
\end{align}
$$
上記の式に対して、$h$はラグであり、$h=0$の$0$次の自己共分散は分散を表すと考える。

以下、前節で取り扱った$AR$過程と同様の例を用いて、標本自己相関係数を元にコレログラムの作成を行い、$(9)$式との比較を行う。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(0)

c = 5.
h = np.arange(0,10,1)
phi = np.array([-0.7, 0, 0.3, 0.5, 0.7])
y = np.zeros([10100,5])
y[0,:] = 2*np.ones(5)

for i in range(1, y.shape[0]):
     y[i, :] = c + phi*y[i-1, :] + stats.norm.rvs(0,size=5)

y_t_h = list()
est_gamma, pop_gamma = np.zeros([10,5]), np.zeros([10,5])

for i in range(h.shape[0]):
    y_t_h.append(y[(100-i):(10100-i),:])
    est_gamma[i,:] = np.sum((y_t_h[0]-np.mean(y_t_h[0],axis=0))*(y_t_h[i]-np.mean(y_t_h[i],axis=0)), axis=0)/y_t_h[0].shape[0]
    pop_gamma[i,:] = (phi**i)/(1.-phi**2)

print("population gamma_h: {}".format(pop_gamma))
print("estimated gamma_h: {}".format(est_gamma))

for i in range(phi.shape[0]):
    plt.plot(h,est_gamma[:,i]/est_gamma[0,i], label="phi: {}".format(phi[i]))

plt.legend()
plt.show()

・実行結果

MA過程のコレログラム

$$
\large
\begin{align}
y_t = \mu + u_t + \theta_{1} u_{t-1} \quad (5)
\end{align}
$$

前節で取り扱った上記のように表される$MA$過程の$h$次の自己共分散は下記のように表される。
$$
\large
\begin{align}
\gamma_{h} &= (1+\theta_{1}^{2}) \sigma^2, \quad h=0 \\
&= \theta_{1} \sigma^2, \quad h=1 \\
&= 0, \quad h>1 \quad (10)
\end{align}
$$
上記の式に対して、$h$はラグであり、$h=0$の$0$次の自己共分散は分散を表すと考える。

以下、前節で取り扱った$MA$過程と同様の例を用いて、標本自己相関係数を元にコレログラムの作成を行い、$(10)$式との比較を行う。

np.random.seed(0)

mu = 2
h = np.arange(0,10,1)
theta = np.array([-0.9, 0., 2.5])
y = np.zeros([10100,3])

u_t_1 = stats.norm.rvs(0,size=3)
for i in range(y.shape[0]):
    u_t = stats.norm.rvs(0,size=3)
    y[i, :] = mu + u_t + theta*u_t_1
    u_t_1 = u_t

y_t_h = list()
est_gamma, pop_gamma = np.zeros([10,3]), np.zeros([10,3])
pop_gamma[0,:], pop_gamma[1,:] = 1+theta**2, theta

for i in range(h.shape[0]):
    y_t_h.append(y[(100-i):(10100-i),:])
    est_gamma[i,:] = np.sum((y_t_h[0]-np.mean(y_t_h[0],axis=0))*(y_t_h[i]-np.mean(y_t_h[i],axis=0)), axis=0)/y_t_h[0].shape[0]

print("population gamma_h: {}".format(pop_gamma))
print("estimated gamma_h: {}".format(est_gamma))

for i in range(theta.shape[0]):
    plt.plot(h,est_gamma[:,i]/est_gamma[0,i], label="phi: {}".format(theta[i]))

plt.legend()
plt.show()

・実行結果

上記の結果は、$MA(1)$過程の$h>1$での自己共分散$\gamma_{h}$が$0$であることに基づくと考えることができる。

ホワイトノイズ

独立と無相関

独立と無相関に関しては混同しがちだが、独立は確率分布に関する前提である一方で無相関は期待値に関する前提であり、それぞれは異なることを把握しておく必要がある。
・独立
$$
\large
\begin{align}
p(x,y) = p(x)p(y)
\end{align}
$$

・無相関
$$
\large
\begin{align}
E[XY] = E[X]E[Y]
\end{align}
$$

上記で表したように、独立は確率分布に関する仮定、無相関は期待値に関する仮定である。$p(x,y)=p(x)p(y) \implies E[XY]=E[X]E[Y]$であるが逆は成立しないことを抑えておく必要がある。独立ならば必ず無相関であるが、無相関でも独立であるとは限らないと考えておくと良い。

以下、「独立かつ無相関」と「無相関であるが独立ではない」事例に関して確認を行う。

import numpy as np
import matplotlib.pyplot as plt

x = np.repeat(np.arange(1.,7.,1.),6)
y = x.reshape([6,6]).T.reshape(36)

x_, y_ = np.repeat(np.arange(1.,7.,1.),6), x.reshape([6,6]).T.reshape(36)
for i in range(6):
    x_[6*i] = 2*(x_[6*i]-3.5)+3.5
    x_[6*i+2] = 0.5*(x_[6*i+2]-3.5)+3.5
    x_[6*i+5] = 2.5*(x_[6*i+5]-3.5)+3.5

cov_xy = np.sum((x-np.mean(x))*(y-np.mean(y)))
cov_xy_ = np.sum((x_-np.mean(x_))*(y_-np.mean(y_)))

print(cov_xy)
print(cov_xy_)

plt.scatter(x_,y_)
plt.show()

・実行結果

> print(cov_xy)
0.0
> print(cov_xy_)
0.0

x_y_は無相関である一方で、x_の値がy_の値によって変化するので独立ではない。このように無相関だが独立ではない場合もあることに注意が必要である。

独立と無相関に関しては下記でも取り扱いを行った。
https://www.hello-statisticians.com/explain-books-cat/toukeigakunyuumon-akahon/ch7_practice.html#73

$i.i.d.$以外のホワイトノイズの例

ホワイトノイズの簡単な例には$u_t \sim N(0,1), \quad i.i.d.,$が考えられるが、ここでは$i.i.d.$以外のホワイトノイズの例に関して確認を行う。

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

np.random.seed(0)

t = np.arange(0,1000,1)
u = np.zeros(1000)
sigma = 1
for i in range(u.shape[0]):
    u[i] = stats.norm.rvs(loc=0,scale=sigma)
    sigma = 1./(np.abs(u[i])+1.)

plt.plot(t,u)
plt.show()

・実行結果

ここで、上記のようにuを生成する場合のコレログラムを作成し、ホワイトノイズであることの確認を行う。

np.random.seed(0)

t = np.arange(0,10100,1)
u = np.zeros(10100)
sigma = 1
for i in range(u.shape[0]):
    u[i] = stats.norm.rvs(loc=0,scale=sigma)
    sigma = 1./(np.abs(u[i])+1.)

h = np.arange(0,10,1)
u_t_h = list()
est_gamma = np.zeros(10)

for i in range(h.shape[0]):
    u_t_h.append(u[(100-i):(10100-i)])
    est_gamma[i] = np.sum((u_t_h[0]-np.mean(u_t_h[0]))*(u_t_h[i]-np.mean(u_t_h[i])))/u_t_h[0].shape[0]

print(np.mean(u))

plt.bar(h,est_gamma)
plt.show()

・実行結果

> print(np.mean(u))
-0.0106528437504

上記より平均と$h>0$での自己共分散が$0$であることが確認できるので、ここで生成されたuがホワイトノイズであると考えることができる。

スペクトラム

検定

単位根検定・ディッキーフラー検定

ダービン・ワトソン検定

ダービン・ワトソン検定(Durbin Watson test)は$u_t$などで表される誤差項に自己相関が存在するかどうかの確認を行う検定である。
$$
\large
\begin{align}
u_{t} = \rho u_{t-1} + \epsilon_{t}
\end{align}
$$

ダービン・ワトソン検定では上記のように誤差項$u_t$が$AR(1)$過程に従うことを仮定する。ここで下記のような帰無仮説$H_0$と対立仮説$H_1$を考える。
$$
\large
\begin{align}
H_0: \quad \rho = 0 \\
H_1: \quad \rho > 0
\end{align}
$$

上記の仮説の検定にあたって、得られた残差$\hat{u}_t$を用いて下記のようにダービン・ワトソン比$DW$を検定統計量に考える。
$$
\large
\begin{align}
DW &= \frac{\sum_{t=2}^{T} (\hat{u}_{t}-\hat{u}_{t-1})^2}{\sum_{t=1}^{T} \hat{u}_{t}^2} = \frac{\sum_{t=2}^{T} \hat{u}_{t}^{2}+\sum_{t=2}^{T} \hat{u}_{t-1}^{2}-2\sum_{t=2}^{T} \hat{u}_{t}\hat{u}_{t-1}}{\sum_{t=1}^{T} \hat{u}_{t}^2} \\
& \simeq 2 \left( 1 – \frac{\sum_{t=2}^{T} \hat{u}_{t}\hat{u}_{t-1}}{\sum_{t=1}^{T} \hat{u}_{t}^2} \right) = 2(1-\hat{\gamma}_1)
\end{align}
$$

上記で定義を行ったダービン・ワトソン比が$2$に近いとき、帰無仮説を受容し、$2$より十分小さな場合に帰無仮説の棄却を行う。

Pythonを用いた推測統計のプログラミング 〜区間推定、仮説検定 etc〜

数式だけの解説ではわかりにくい場合もあると思われるので、統計学の手法や関連する概念をPythonのプログラミングで表現を行います。当記事では統計的推測(statistical inference)の理解にあたって、区間推定や仮説検定のPythonでの実装を取り扱いました。

・Pythonを用いた統計学のプログラミングまとめ
https://www.hello-statisticians.com/stat_program

基本事項の確認

区間推定

下記で詳しく取り扱った。
https://www.hello-statisticians.com/explain-terms-cat/flow_chart_stat1.html

仮説検定

推測統計でよく用いるSciPyのメソッド

SciPyの使用にあたっては、scipy.stats.xxx.oooのように使用するメソッドの指定を行うが、xxxに確率分布、oooに行う処理を指定する。

推測統計ではxxxに対して主に下記などの確率分布の指定を行う。

norm: 正規分布
t: $t$分布
chi2: $\chi^2$分布

同様に推測統計ではoooに対して、主に下記の処理の指定を行う。

cdf: 統計量から有意水準・$P$値の計算
ppf: 有意水準・$P$値から統計量の計算
pdf: 統計量から確率密度関数の計算

特にcdfppfは区間推定や検定で統計数値表の代わりに用いることができる。

以下、標準正規分布を例にcdfppfpdfの概要の確認を行う。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

x = np.arange(-3.,3.01,0.01)
f_pdf = stats.norm.pdf(x)
F_cdf = stats.norm.cdf(x)

plt.plot(x,f_pdf,label="pdf")
plt.plot(x,F_cdf,label="cdf")

plt.legend()
plt.show()

・実行結果

上記のようにcdfpdfを用いることで累積分布関数と確率密度関数の描画を行うことができる。

次に、cdfppfの対応に関して確認を行う。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

alpha = np.array([0.1, 0.05, 0.025, 0.01, 0.005])
x = np.arange(-3.,3.01,0.01)
F_cdf = stats.norm.cdf(x)

plt.plot(x,F_cdf,label="cdf")
for i in range(alpha.shape[0]):
    print("alpha: {}, statistic_upper: {:.2f}".format(alpha[i], stats.norm.ppf(1.-alpha[i])))
    x_upper = np.repeat(stats.norm.ppf(1.-alpha[i]), 100)
    y = np.linspace(0,1.-alpha[i],100)
    plt.plot(x_upper,y,label="alpha: {}".format(alpha[i]))

plt.legend(loc=2)
plt.show()

・実行結果

alpha: 0.1, statistic_upper: 1.28
alpha: 0.05, statistic_upper: 1.64
alpha: 0.025, statistic_upper: 1.96
alpha: 0.01, statistic_upper: 2.33
alpha: 0.005, statistic_upper: 2.58

上記よりcdfppfは逆関数であると考えることができる。それぞれの対応がわかりやすいように、下記では上図の編集を行った。

統計数値表とSciPyを用いた代用

scipy.statsscipy.stats.normscipy.stats.tscipy.stats.chi2を用いることで、統計的推測を行うことができる。特に区間推定や仮説検定でよく用いられる統計数値表が、累積分布関数に対応するscipy.stats.norm.cdfなどを活用することで作成できることは抑えておくと良い。

以下ではscipy.stats.norm.cdfscipy.stats.norm.ppfなどを用いることで統計数値表を作成し概要の理解を行うことに加えて、SciPyで代用する際の用い方について確認を行う。

標準正規分布

統計数値表の作成

上側確率が$100 \alpha’$%となる点を$z_{\alpha=\alpha’}$とおくとき、$z_{\alpha=\alpha’}=0$から$0.01$刻みで該当する$\alpha’$の値を表形式で表したものが統計数値表である。以下、$500$個の値を$50$行$10$列に並べることで標準正規分布の統計数値表の作成を行う。

import numpy as np
from scipy import stats

z = np.arange(0., 5., 0.01).reshape([50,10])
table_norm = 1. - stats.norm.cdf(z)

print(table_norm)

・実行結果

array([[  5.00000000e-01,   4.96010644e-01,   4.92021686e-01,
          4.88033527e-01,   4.84046563e-01,   4.80061194e-01,
          4.76077817e-01,   4.72096830e-01,   4.68118628e-01,
          4.64143607e-01],
       [  4.60172163e-01,   4.56204687e-01,   4.52241574e-01,
          4.48283213e-01,   4.44329995e-01,   4.40382308e-01,
          4.36440537e-01,   4.32505068e-01,   4.28576284e-01,
          4.24654565e-01],
.....
[  4.79183277e-07,   4.55381965e-07,   4.32721062e-07,
          4.11148084e-07,   3.90612854e-07,   3.71067408e-07,
          3.52465898e-07,   3.34764508e-07,   3.17921366e-07,
          3.01896462e-07]])

処理の理解にあたっては、上側確率であることから1. - stats.norm.cdf(z)のように$1$から引いたと考えると良い。

SciPyを用いた統計数値表の代用

・有意水準$\alpha$から標準化変量$Z$を導出

有意水準$\alpha$から標準化変量$Z$を導出する場合はscipy.stats.norm.ppfを用いればよい。

import numpy as np
from scipy import stats

alpha = np.array([0.1, 0.05, 0.025, 0.01, 0.005])
Z_Limit = stats.norm.ppf(1.-alpha)

print(Z_Limit)

・実行結果

> print(Z_Limit)
array([ 1.28155157,  1.64485363,  1.95996398,  2.32634787,  2.5758293 ])

標準化変量$Z$から有意水準$\alpha$を導出

標準化変量$Z$から有意水準$\alpha$を導出する場合は、統計数値表の作成と同様にscipy.stats.norm.cdfを用いればよい。

import numpy as np
from scipy import stats

Z = np.array([0., 0.5, 1., 1.5, 2., 2.5, 3.])
alpha = 1.-stats.norm.cdf(Z)

print(alpha)

・実行結果

> print(alpha)
[ 0.5         0.30853754  0.15865525  0.0668072   0.02275013  0.00620967
  0.0013499 ]

$t$分布

統計数値表の作成

自由度が$\nu$の$t$分布$t(\nu)$に関して、上側確率が$100 \alpha’$%となる点を$t_{\alpha=\alpha’}(\nu)$とおくとき、$\alpha’=\{0.25, 0.20, 0.15, 0.10, 0.05, 0.025, 0.01, 0.005, 0.001\}$に対して、$\nu$を変化させたときに$t_{\alpha=\alpha’}(\nu)$の値をまとめたものが$t$分布の統計数値表である。以下、それぞれの有意水準と自由度に対して$t$分布の統計数値表の作成を行う。

import numpy as np
from scipy import stats

alpha = np.array([0.25, 0.20, 0.15, 0.10, 0.05, 0.025, 0.01, 0.005, 0.0005])
nu = np.arange(1,56,1)
nu[50:] = np.array([60., 80., 120., 240., 100000])

table_t = np.zeros([nu.shape[0],alpha.shape[0]])
for i in range(nu.shape[0]):
    table_t[i,:] = stats.t.ppf(1.-alpha,nu[i])

print(table_t)

・実行結果

[[   1.            1.37638192    1.96261051    3.07768354    6.31375151
    12.70620474   31.82051595   63.65674116  636.61924943]
 [   0.81649658    1.06066017    1.38620656    1.88561808    2.91998558
     4.30265273    6.96455672    9.9248432    31.59905458]
 [   0.76489233    0.97847231    1.2497781     1.63774436    2.35336343
     3.18244631    4.54070286    5.8409093    12.92397864]
.....
 [   0.67551336    0.84312147    1.0386776     1.28508893    1.65122739
     1.96989764    2.34198547    2.59646918    3.33152484]
 [   0.6744922     0.84162483    1.03643876    1.28156003    1.64486886
     1.95998771    2.32638517    2.57587847    3.29062403]]

処理の理解にあたっては、上側確率であることから1. - alphaのように$1$から引いたと考えると良い。

SciPyを用いた統計数値表の代用

・有意水準$\alpha$からパーセント点$t_{\alpha=\alpha’}(\nu)$を導出

有意水準$\alpha$からパーセント点$t_{\alpha=\alpha’}(\nu)$を導出する場合は統計数値表の作成と同様にscipy.stats.t.ppfを用いればよい。

import numpy as np
from scipy import stats

alpha = np.array([0.1, 0.05, 0.025, 0.01, 0.005])
Z_Limit = stats.norm.ppf(1.-alpha)
t_Limit_20 = stats.t.ppf(1.-alpha, 20)
t_Limit_100 = stats.t.ppf(1.-alpha, 100)

print(Z_Limit)
print(t_Limit_20)
print(t_Limit_100)

・実行結果

> print(Z_Limit)
[ 1.28155157  1.64485363  1.95996398  2.32634787  2.5758293 ]
> print(t_Limit_20)
[ 1.32534071  1.72471824  2.08596345  2.527977    2.84533971]
> print(t_Limit_100)
[ 1.29007476  1.66023433  1.98397152  2.36421737  2.62589052]

上記より、$t$分布の棄却点は標準正規分布の棄却点より絶対値が大きくなることが確認できる。また、t_Limit_20t_Limit_100の比較により、自由度が大きくなるにつれて$t$分布が標準正規分布に近づくことも確認できる。

・パーセント点$t_{\alpha=\alpha’}(\nu)$から有意水準$\alpha$を導出

統計量$t$から有意水準$\alpha$を導出する場合は、scipy.stats.t.cdfを用いればよい。

import numpy as np
from scipy import stats

t = np.array([0., 0.5, 1., 1.5, 2., 2.5, 3.])
alpha_20 = 1.-stats.t.cdf(t,20)
alpha_100 = 1.-stats.t.cdf(t,100)

print(alpha_20)
print(alpha_100)

・実行結果

> print(alpha_20)
[ 0.5         0.31126592  0.16462829  0.07461789  0.02963277  0.01061677
  0.00353795]
> print(alpha_100)
[ 0.5         0.30908678  0.15986208  0.06838253  0.02410609  0.00702289
  0.00170396]

$\chi^2$分布

統計数値表の作成

自由度が$\nu$の$\chi^2$分布$\chi^2(\nu)$に関して、上側確率が$100 \alpha’$%となる点を$\chi^2_{\alpha=\alpha’}(\nu)$とおくとき、$\alpha’=\{0.995, 0.990, 0.975, 0.950, 0.900, 0.800, …, 0.100, 0.050, 0.025, 0.010, 0.005, 0.001\}$に対して、$\nu$を変化させたときに$t_{\alpha=\alpha’}(\nu)$の値をまとめたものが「基礎統計学Ⅰ」における$\chi^2$分布の統計数値表である。以下、それぞれの有意水準と自由度に対して$\chi^2$分布の統計数値表の作成を行う。

import numpy as np
from scipy import stats

alpha = np.array([0.995, 0.990, 0.975, 0.95, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.05, 0.025, 0.01, 0.005, 0.001])
nu = np.arange(1,62,1)
nu[50:] = np.array([60., 70., 80., 90., 100., 120., 140., 160., 180., 200., 240.])

table_chi2 = np.zeros([nu.shape[0],alpha.shape[0]])
for i in range(nu.shape[0]):
    table_chi2[i,:] = stats.chi2.ppf(1.-alpha,nu[i])

print(table_chi2)

・実行結果

[[  3.92704222e-05   1.57087858e-04   9.82069117e-04 ...,   6.63489660e+00
    7.87943858e+00   1.08275662e+01]
 [  1.00250836e-02   2.01006717e-02   5.06356160e-02 ...,   9.21034037e+00
    1.05966347e+01   1.38155106e+01]
 [  7.17217746e-02   1.14831802e-01   2.15795283e-01 ...,   1.13448667e+01
    1.28381565e+01   1.62662362e+01]
.....
 [  1.52240992e+02   1.56431966e+02   1.62727983e+02 ...,   2.49445123e+02
    2.55264155e+02   2.67540528e+02]
 [  1.87324255e+02   1.91989896e+02   1.98983851e+02 ...,   2.93888101e+02
    3.00182237e+02   3.13436899e+02]]

SciPyを用いた統計数値表の代用

・有意水準$\alpha$からパーセント点$\chi^2_{\alpha=\alpha’}(\nu)$を導出

有意水準$\alpha$からパーセント点$\chi^2_{\alpha=\alpha’}(\nu)$を導出する場合は統計数値表の作成と同様にscipy.stats.chi2.ppfを用いればよい。

import numpy as np
from scipy import stats

alpha = np.array([0.975, 0.95, 0.1, 0.05, 0.025])
chi2_Limit_1 = stats.chi2.ppf(1.-alpha, 1)
chi2_Limit_10 = stats.chi2.ppf(1.-alpha, 10)
chi2_Limit_100 = stats.chi2.ppf(1.-alpha, 100)

print(chi2_Limit_1)
print(chi2_Limit_10)
print(chi2_Limit_100)

・実行結果

print(chi2_Limit_1)
[  9.82069117e-04   3.93214000e-03   2.70554345e+00   3.84145882e+00
   5.02388619e+00]
print(chi2_Limit_10)
[  3.24697278   3.94029914  15.98717917  18.30703805  20.48317735]
print(chi2_Limit_100)
[  74.22192747   77.92946517  118.49800381  124.3421134   129.56119719]

・パーセント点$\chi^2_{\alpha=\alpha’}(\nu)$から有意水準$\alpha$を導出

統計量$\chi^2$から有意水準$\alpha$を導出する場合は、scipy.stats.chi2.cdfを用いればよい。

import numpy as np
from scipy import stats

chi2 = np.array([2., 5., 10., 15., 20., 50., 100.])

alpha_1 = 1.-stats.chi2.cdf(chi2,1)
alpha_5 = 1.-stats.chi2.cdf(chi2,5)
alpha_10 = 1.-stats.chi2.cdf(chi2,10)
alpha_20 = 1.-stats.chi2.cdf(chi2,20)
alpha_100 = 1.-stats.chi2.cdf(chi2,100)

print(alpha_1)
print(alpha_5)
print(alpha_10)
print(alpha_20)
print(alpha_100)

・実行結果

> print(alpha_1)
[  1.57299207e-01   2.53473187e-02   1.56540226e-03   1.07511177e-04
   7.74421643e-06   1.53743684e-12   0.00000000e+00]
> print(alpha_5)
[  8.49145036e-01   4.15880187e-01   7.52352461e-02   1.03623379e-02
   1.24973056e-03   1.38579737e-09   0.00000000e+00]
> print(alpha_10)
[  9.96340153e-01   8.91178019e-01   4.40493285e-01   1.32061856e-01
   2.92526881e-02   2.66908343e-07   0.00000000e+00]
> print(alpha_20)
[  9.99999889e-01   9.99722648e-01   9.68171943e-01   7.76407613e-01
   4.57929714e-01   2.21476638e-04   1.25965904e-12]
> print(alpha_100)
[ 1.          1.          1.          1.          1.          0.99999305
  0.48119168]

区間推定・仮説検定

母分散既知の場合の母平均

区間推定

$$
\large
\begin{align}
\bar{x}-1.96\frac{\sigma}{\sqrt{n}} \leq &\mu \leq \bar{x}+1.96\frac{\sigma}{\sqrt{n}}
\end{align}
$$
母平均の$95$%区間推定は上記のように表される。以下、上記を元に具体的な例に対して計算を行う。

import numpy as np
from scipy import stats

sigma = 1.
x = np.array([1.2, 1.5, 0.9, 0.7, 1.1])
ave_x = np.mean(x)

Lower_mu = ave_x + stats.norm.ppf(0.025)*sigma/np.sqrt(x.shape[0])
Upper_mu = ave_x + stats.norm.ppf(0.975)*sigma/np.sqrt(x.shape[0])

print("Estimated mu-interval: [{:.3f}, {:.3f}]".format(Lower_mu, Upper_mu))

・実行結果

> print("Estimated mu-interval: [{:.3f}, {:.3f}]".format(Lower_mu, Upper_mu))
Estimated mu-interval: [0.203, 1.957]

以下、$\sigma$の値を変化させた際の区間推定の結果の確認を行う。

import numpy as np
from scipy import stats

sigma = np.array([0.1, 0.25, 0.5, 1., 2.])
x = np.array([1.2, 1.5, 0.9, 0.7, 1.1])
ave_x = np.mean(x)

Lower_mu = ave_x + stats.norm.ppf(0.025)*sigma/np.sqrt(x.shape[0])
Upper_mu = ave_x + stats.norm.ppf(0.975)*sigma/np.sqrt(x.shape[0])

for i in range(sigma.shape[0]):
    print("Estimated mu-interval: [{:.3f}, {:.3f}]".format(Lower_mu[i], Upper_mu[i]))

・実行結果

Estimated mu-interval: [0.992, 1.168]
Estimated mu-interval: [0.861, 1.299]
Estimated mu-interval: [0.642, 1.518]
Estimated mu-interval: [0.203, 1.957]
Estimated mu-interval: [-0.673, 2.833]

Lower_muUpper_muの計算にあたって、それぞれ0.0250.975を引数に設定したが、これは上側確率を$\alpha’$とおく際の$1-\alpha’$に対応し、このように考えると少々わかりにくい。そのため、標準正規分布の累積分布関数の値から変数の値を計算すると考える方が良い。

これらの違いは元々が「統計数値表」に基づいて考えていた一方で、SciPyなどで実装を行う際には「数値表」が必要ないことからより関数的な表し方に変わったのではないかと考えられる。

SciPyでの表し方がより自然に思われるので、表よりもSciPyなどを用いた形式で理解する方がわかりやすいかもしれない。

仮説検定① 〜norm.ppfと区間推定の活用〜

前項のxave_xに対し、帰無仮説を$H_0: \mu=0$と設定し、上側確率$\alpha’=\{0.05, 0.025, 0.005\}$を用いた仮説検定を行う。
$$
\large
\begin{align}
z_{\alpha=1-\alpha’} \leq &\frac{\bar{x}-\mu}{\sigma/\sqrt{n}} \leq z_{\alpha=\alpha’} \\
-z_{\alpha=\alpha’} \leq &\frac{\sqrt{n}}{\sigma}\bar{x} \leq z_{\alpha=\alpha’}
\end{align}
$$
ここでの検定統計量の$\displaystyle Z = \frac{\sqrt{n}}{\sigma}\bar{x}$に関して上記が成立しなければ$H_0$を棄却し、対立仮説の$H_1: \mu \neq 0$を採択する。

import numpy as np
from scipy import stats

alpha = np.array([0.05, 0.025, 0.005])
sigma = 1.
x = np.array([1.2, 1.5, 0.9, 0.7, 1.1])
Z_observed = np.sqrt(x.shape[0])*np.mean(x)/sigma

Lower_Z = -stats.norm.ppf(1.-alpha)*sigma
Upper_Z = stats.norm.ppf(1.-alpha)*sigma

for i in range(alpha.shape[0]):
    if Z_observed > Upper_Z[i] or Z_observed < Lower_Z[i]:
        print("Z: {:.3f}. If alpha: {} -> Upper_Z: {:.2f}, reject H_0: mu=0. ".format(Z_observed, alpha[i], Upper_Z[i]))
    else:
        print("Z: {:.3f}. If alpha: {} -> Upper_Z: {:.2f}, accept H_0: mu=0. ".format(Z_observed, alpha[i], Upper_Z[i]))

・実行結果

Z: 2.415. If alpha: 0.05 -> Upper_Z: 1.64, reject H_0: mu=0. 
Z: 2.415. If alpha: 0.025 -> Upper_Z: 1.96, reject H_0: mu=0. 
Z: 2.415. If alpha: 0.005 -> Upper_Z: 2.58, accept H_0: mu=0.

上記より、上側確率を小さくするにつれて棄却されにくいことが確認できる。

仮説検定② 〜norm.cdfと$P$値の活用〜

前項の「仮説検定①」では区間推定の結果と$Z$の値を元に検定を行なったが、$Z$の値に対してnorm.cdfを用いることで$P$値を計算し、検定を行うこともできる。

import numpy as np
from scipy import stats

alpha = np.array([0.05, 0.025, 0.005])
sigma = 1.
x = np.array([1.2, 1.5, 0.9, 0.7, 1.1])
Z_observed = np.sqrt(x.shape[0])*np.mean(x)/sigma

P_value = 1.-stats.norm.cdf(Z_observed)

for i in range(alpha.shape[0]):
    if P_value > 1.-alpha[i] or P_value < alpha[i]:
        print("Z: {:.3f}, P_value: {:.3f}. If alpha: {}, reject H_0: mu=0. ".format(Z_observed, P_value, alpha[i]))
    else:
        print("Z: {:.3f}, P_value: {:.3f}. If alpha: {}, accept H_0: mu=0. ".format(Z_observed, P_value, alpha[i]))

・実行結果

Z: 2.415, P_value: 0.008. If alpha: 0.05, reject H_0: mu=0. 
Z: 2.415, P_value: 0.008. If alpha: 0.025, reject H_0: mu=0. 
Z: 2.415, P_value: 0.008. If alpha: 0.005, accept H_0: mu=0. 

仮説検定は②で取り扱った「$P$値の活用」を用いる方が「ノンパラメトリック法」と同様に取り扱うことができるなど、わかりやすい。また、この際にppfcdfの図を元に下記のように考えることもできる。

母分散未知の場合の母平均

区間推定

$$
\large
\begin{align}
\bar{x}-t_{\alpha=0.025}(n-1) \frac{s}{\sqrt{n}} \leq &\mu \leq \bar{x}+t_{\alpha=0.025}(n-1) \frac{s}{\sqrt{n}} \\
s = \frac{1}{n-1} & \sum_{i=1}^{n} (x_i-\bar{x})^2
\end{align}
$$
母分散が未知の際の母平均の$95$%区間推定は上記のように表される。以下、上記を元に具体的な例に対して計算を行う。

import numpy as np
from scipy import stats

x = np.array([1.2, 1.5, 0.9, 0.7, 1.1])
ave_x = np.mean(x)
s = np.sqrt(np.sum((x-ave_x)**2/(x.shape[0]-1)))

Lower_mu = ave_x - stats.t.ppf(1-0.025, x.shape[0]-1)*s/np.sqrt(x.shape[0])
Upper_mu = ave_x + stats.t.ppf(1-0.025, x.shape[0]-1)*s/np.sqrt(x.shape[0])

print("s: {:.2f}".format(s))
print("Estimated mu-interval: [{:.3f}, {:.3f}]".format(Lower_mu, Upper_mu))

・実行結果

> print("s: {:.2f}".format(s))
s: 0.30
> print("Estimated mu-interval: [{:.3f}, {:.3f}]".format(Lower_mu, Upper_mu))
Estimated mu-interval: [0.703, 1.457]

母分散既知の場合と同様の事例を用いたが、$s=0.3$の周辺の$\sigma=0.25$の際の区間が[0.861, 1.299]、$\sigma=0.5$の際の区間が[0.642, 1.518]であったので、概ね同様の結果が得られていることが確認できる。

仮説検定

前項のxave_xに対し、帰無仮説を$H_0: \mu_0=0.95$と設定し、上側確率$\alpha’=\{0.05, 0.025, 0.005\}$を用いた仮説検定を行う。
$$
\large
\begin{align}
t_{\alpha=1-\alpha’}(n-1) \leq &\frac{\bar{x}-\mu_0}{s/\sqrt{n}} \leq t_{\alpha=\alpha’}(n-1) \\
-t_{\alpha=\alpha’}(n-1) \leq &\frac{\sqrt{n}}{s} (\bar{x}-0.95) \leq t_{\alpha=\alpha’}(n-1)
\end{align}
$$
ここでの検定統計量の$\displaystyle t = \frac{\sqrt{n}}{s} (\bar{x}-\mu_0)$に関して上記が成立しなければ$H_0$を棄却し、対立仮説の$H_1: \mu_0 \neq 0.95$を採択する。

import numpy as np
from scipy import stats

mu_0 = 0.95
alpha = np.array([0.05, 0.025, 0.005]) 

x = np.array([1.2, 1.5, 0.9, 0.7, 1.1])
ave_x = np.mean(x)
s = np.sqrt(np.sum((x-ave_x)**2/(x.shape[0]-1)))
t_observed = np.sqrt(x.shape[0])*(ave_x-mu_0)/s

Lower_t = -stats.t.ppf(1.-alpha, x.shape[0])*s
Upper_t = stats.t.ppf(1.-alpha, x.shape[0])*s

for i in range(alpha.shape[0]):
    if t_observed > Upper_t[i] or t_observed < Lower_t[i]:
        print("t: {:.3f}. If alpha: {}, reject H_0: mu=0. ".format(t_observed, alpha[i]))
    else:
        print("t: {:.3f}. If alpha: {}, accept H_0: mu=0. ".format(t_observed, alpha[i]))

print(Lower_t)
print(Upper_t)

・実行結果

t: 0.958. If alpha: 0.05, reject H_0: mu=0. 
t: 0.958. If alpha: 0.025, reject H_0: mu=0. 
t: 0.958. If alpha: 0.005, accept H_0: mu=0. 

> print(Lower_t)
[-0.61119443 -0.77969608 -1.22300952]
> print(Upper_t)
[ 0.61119443  0.77969608  1.22300952]

上記より、上側確率を小さくするにつれて棄却されにくいことが確認できる。

母分散

区間推定

$$
\large
\begin{align}
\frac{(n-1)s^2}{\chi_{\alpha=0.025}^2(n-1)} \leq & \sigma^2 \leq \frac{(n-1)s^2}{\chi_{\alpha=0.975}^2(n-1)} \\
s = \frac{1}{n-1} & \sum_{i=1}^{n} (x_i-\bar{x})^2
\end{align}
$$
母分散の$95$%区間推定は上記のように表される。以下、上記を元に具体的な例に対して計算を行う。

import numpy as np
from scipy import stats

x = np.array([1.2, 1.5, 0.9, 0.7, 1.1])
ave_x = np.mean(x)
s = np.sqrt(np.sum((x-ave_x)**2/(x.shape[0]-1)))

Lower_sigma2 = (x.shape[0]-1)*s**2/stats.chi2.ppf(1.-0.025, x.shape[0]-1)
Upper_sigma2 = (x.shape[0]-1)*s**2/stats.chi2.ppf(1.-0.975, x.shape[0]-1)

print("s^2: {:.2f}".format(s**2))
print("Estimated sigma2s-interval: [{:.3f}, {:.3f}]".format(Lower_sigma2, Upper_sigma2))

・実行結果

> print("s^2: {:.2f}".format(s**2))
s^2: 0.09
> print("Estimated sigma2s-interval: [{:.3f}, {:.3f}]".format(Lower_sigma2, Upper_sigma2))
Estimated sigma2s-interval: [0.033, 0.760]

以下、サンプルを増やした際に$95$%区間はどのように変化するかに関して確認を行う。

import numpy as np
from scipy import stats

x = np.array([1.2, 1.5, 0.9, 0.7, 1.1, 0.5, 1.0, 1.3, 0.9, 1.2])
ave_x = np.mean(x)
s = np.sqrt(np.sum((x-ave_x)**2/(x.shape[0]-1)))

Lower_sigma2 = (x.shape[0]-1)*s**2/stats.chi2.ppf(1.-0.025, x.shape[0]-1)
Upper_sigma2 = (x.shape[0]-1)*s**2/stats.chi2.ppf(1.-0.975, x.shape[0]-1)

print("s^2: {:.2f}".format(s**2))
print("Estimated sigma2s-interval: [{:.3f}, {:.3f}]".format(Lower_sigma2, Upper_sigma2))

・実行結果

> print("s^2: {:.2f}".format(s**2))
s^2: 0.09
> print("Estimated sigma2s-interval: [{:.3f}, {:.3f}]".format(Lower_sigma2, Upper_sigma2))
Estimated sigma2s-interval: [0.041, 0.289]

上記よりサンプルを増やすと$\sigma^2$の$95$%区間が小さくなることが確認できる。

仮説検定

前項のxに対し、帰無仮説を$H_0: \sigma_0^2=0.3$と設定し、上側確率$\alpha’=\{0.05, 0.025, 0.005\}$を用いた仮説検定を行う。
$$
\large
\begin{align}
\chi_{\alpha=0.975}(n-1) \leq & \frac{(n-1)s^2}{\sigma_0^2} \leq \chi_{\alpha=0.025}(n-1) \\
s = \frac{1}{n-1} & \sum_{i=1}^{n} (x_i-\bar{x})^2
\end{align}
$$
ここでの検定統計量の$\displaystyle \chi^2 = \frac{(n-1)s^2}{\sigma_0^2}$に関して上記が成立しなければ$H_0$を棄却し、対立仮説の$H_1: \sigma^2 \neq 0.3$を採択する。

import numpy as np
from scipy import stats

sigma2_0 = 0.3
alpha = np.array([0.05, 0.025, 0.005]) 

x = np.array([1.2, 1.5, 0.9, 0.7, 1.1, 0.5, 1.0, 1.3, 0.9, 1.2])
ave_x = np.mean(x)
s = np.sqrt(np.sum((x-ave_x)**2/(x.shape[0]-1)))

chi2_observed = (x.shape[0]-1)*s**2/sigma2_0

Lower_chi2 = stats.chi2.ppf(alpha, x.shape[0]-1)
Upper_chi2 = stats.chi2.ppf(1.-alpha, x.shape[0]-1)

for i in range(alpha.shape[0]):
    if chi2_observed > Upper_chi2[i] or chi2_observed < Lower_chi2[i]:
        print("chi2: {:.3f}. If alpha: {}, reject H_0: sigma^2=0.3. ".format(chi2_observed, alpha[i]))
    else:
        print("chi2: {:.3f}. If alpha: {}, accept H_0: sigma^2=0.3. ".format(chi2_observed, alpha[i]))

print(Lower_chi2)
print(Upper_chi2)

・実行結果

chi2: 2.603. If alpha: 0.05, reject H_0: sigma^2=0.3. 
chi2: 2.603. If alpha: 0.025, reject H_0: sigma^2=0.3. 
chi2: 2.603. If alpha: 0.005, accept H_0: sigma^2=0.3. 

> print(Lower_t)
[ 3.32511284  2.7003895   1.7349329 ]
> print(Upper_t)
[ 16.9189776   19.0227678   23.58935078]

上記より、上側確率を小さくするにつれて棄却されにくいことが確認できる。

母平均の差

区間推定

仮説検定

母分散の比

区間推定

仮説検定

「統計学実践ワークブック」 演習問題etc Ch.11 「正規分布に関する検定」

当記事は「統計学実践ワークブック(学術図書出版社)」の読解サポートにあたってChapter.11の「正規分布に関する検定」に関して演習問題を中心に解説を行います。正規分布を用いた検定はよく用いられる手法なので、演習を通して抑えておくと良いと思われました。

本章のまとめ

演習問題解説

問11.1

$[1]$
検定統計量は下記を実行することで計算できる。

import numpy as np

t_stat = (125.-120.)/(10./np.sqrt(10))

print("T-statistic: {:.3f}".format(t_stat))

・実行結果

> print("T-statistic: {:.3f}".format(t_stat))
T-statistic: 1.581

$[2]$
$[1]$で計算した統計量は自由度$10-1=9$の$t$分布$t(9)$に従う。よって、上側$2.5$%の棄却限界点は下記を実行することで求められる。

from scipy import stats

print("Upper limit: {:.3f}".format(stats.t.ppf(0.975, 9)))

・実行結果

> print("Upper limit: {:.3f}".format(stats.t.ppf(0.975, 9)))
Upper limit: 2.262

$[3]$
$1.581<2.262$であるので棄却されない。

$[4]$
$$
\large
\begin{align}
\frac{125-120}{\frac{10}{\sqrt{n}}} &> t_{\alpha=0.025}(n-1) \\
n &> 4 t_{\alpha=0.025}(n-1)^2
\end{align}
$$

上記を$n$に関して解けば良い。下記を実行することで不等号が成立する最小の$n$を求めることができる。

from scipy import stats

for i in range(10, 20):
    t_ = 4*stats.t.ppf(0.975,i)**2
    print("n: {}, 4t(n-1)^2: {:.2f}".format(i+1, t_))

・実行結果

n: 11, 4t(n-1)^2: 19.86
n: 12, 4t(n-1)^2: 19.38
n: 13, 4t(n-1)^2: 18.99
n: 14, 4t(n-1)^2: 18.67
n: 15, 4t(n-1)^2: 18.40
n: 16, 4t(n-1)^2: 18.17
n: 17, 4t(n-1)^2: 17.98
n: 18, 4t(n-1)^2: 17.81
n: 19, 4t(n-1)^2: 17.66
n: 20, 4t(n-1)^2: 17.52

上記より、$n=18$がここでの最小の標本サイズであることがわかる。

問11.2

$1)$
下記を実行することで分散の不偏推定値を計算することができる。

s = ((10.-1.)*10.**2 + (10.-1.)*8**2)/(10.+10.-2.)

print("Estimated s^2: {:.1f}".format(s))

・実行結果

> print("Estimated s^2: {:.1f}".format(s))
Estimated s^2: 82.0

$2)$
検定統計量$t$の値は下記を実行することで計算できる。

import numpy as np

t = (125.-115.)/(np.sqrt(82.)*np.sqrt(1./10.+1./10.))

print("t-statistic: {:.3f}".format(t))

・実行結果

> print("t-statistic: {:.3f}".format(t))
t-statistic: 2.469

$3)$
自由度が$10+10-2=18$であるので、棄却限界値は統計数値表より、$t_{\alpha=0.025}(18) = 2.101$であることがわかる。

scipy.stats.t.ppfを用いて、下記を実行することで値を得ることもできる。

from scipy import stats 

print(stats.t.ppf(1.-0.025,18))

$4)$
$t=2.469>2.101=t_{\alpha=0.025}(18)$より、帰無仮説は棄却され、対立仮説の$H_1: \mu_A \neq \mu_B$が採択される。

参考

・準1級関連まとめ
https://www.hello-statisticians.com/toukeikentei-semi1