Up

2 統計量

 

本書第2章に関係する統計量、平均値・分散・標準偏差歪度尖度四分位数箱ひげ図共分散と相関係数回帰直線偏相関係数順位相関係数の計算Pythonスクリプト例を以下のように書いてみた。スクリプトファイルなどは圧縮ファイルchap2_files.zipにまとめた。ダウンロード・展開して自由に利用されたい。

Jupyter Notebook用にまとめたものも用意して、圧縮ファイルchap2_prgs.zipとした。こちらもダウンロード・展開して自由に利用されたい。

 

 

平均値・分散・標準偏差

 

平均値、分散、標準偏差を定義に基づいて計算する場合と、Pythonの関数を用いる場合のコードを、リスト2.1のように書いてみた。

 

リスト2.1 平均値・分散・標準偏差の計算スクリプト例(s2_mn_sd_a.py

 

import numpy as np

 

data = [5, 6, 6, 8]

 

v = 0.0

for t in data:

    v += t

v_mean = v / len(data)

print('平均値 =', v_mean)

print('平均値 =', np.mean(data))

 

v = 0.0

for t in data:

    v += (t - v_mean) ** 2

v_S2 = v / len(data)

v_s2 = v / (len(data) - 1)

print('分散 =', v_S2)

print('不偏分散 =', v_s2)

print(np.var(data, ddof = 0))

print(np.var(data, ddof = 1))

 

v_S = v_S2 ** 0.5

v_s = v_s2 ** 0.5

print('S =', v_S)

print('s =', v_s)

print(np.std(data, ddof = 0))

print(np.std(data, ddof = 1))

 

パラメータddofは、和を(データの個数―ddof)で割ることを示す。

リスト2.1を実行すると、以下の出力が得られる。

 

平均値 = 6.25

平均値 = 6.25

分散 = 1.1875

不偏分散 = 1.5833333333333333

1.1875

1.5833333333333333

S = 1.0897247358851685

s = 1.2583057392117916

1.0897247358851685

1.2583057392117916

 

 

歪度

 

歪度を本書2.1.16)によって算出する場合とPythonの関数を用いる場合のスクリプト例をリスト2.2に示す。

 

リスト2.2 歪度の計算(s2_skewness.py

 

import scipy.stats as ss

import numpy as np

 

data = [1]*10 +[2,3,4,5,6,7,8,9,10]

print(data)

data = np.array(data)   #   ndarray型に変換

 

m = np.mean(data)

S = np.std(data, ddof = 0)

 

g = np.mean((((data - m) / S) ** 3))

print(g)

print(ss.skew(data))

 

リスト2.2を実行すると、以下の出力を得る。

 

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

0.9233534786348041

0.9233534786348037

 

浮動小数点の計算精度で同じ値である。

 

 

尖度

 

尖度を本書2.1.17)式によって計算するコードと、Pythonの関数によって求める場合のスクリプト例をリスト2.3に示す。

 

リスト2.3 尖度の計算(s2_kurtosis.py

 

import numpy as np

import scipy.stats as ss

 

data = [1,2,3,4,5,6,7,8,9,10] * 2

print(data)

 

data = np.array(data)

m = np.mean(data)

S = np.std(data, ddof = 0)

 

g2 = np.mean((((data - m) / S) ** 4))

print(g2)

print(ss.kurtosis(data, fisher = False))

 

print(g2-3)

print(ss.kurtosis(data, fisher = True))

 

パラメータfisherの値がFalseであれば、式(2.1.17)による値が、Trueであれば式(2.1.17)から3を引いた値が返される。

リスト2.3を実行すると以下の出力が得られる。

 

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

1.7757575757575759

1.7757575757575756

-1.2242424242424241

-1.2242424242424244

 

 

四分位数

 

データ「10, 20, 30, 40」の四分位数を求めるスクリプトをリスト2.4のように作成した。

 

リスト2.4 四分位数を求めるスクリプト(s2_percentiles.py

 

import numpy as np

 

data = [10, 20, 30, 40]

print(data)

 

Qs = np.percentile(data, [25, 50, 75])

print(Qs)

 

リスト2.4を実行すると以下の出力を得る。

 

[10, 20, 30, 40]

[17.5 25.  32.5]

 

中央値が25となっているが、第1四分位数と第3四分位数は17.532.5で、それぞれ1020、および3040の中間ではない。

これらが中間の値になるように求める関数例が、岡本安晴「いまさら聞けないPythonでデータ分析」丸善出版p.11MyPercentileとして載っている。これを用いたスクリプト例をリスト2.5に示す。

 

リスト2.5 ウエイトを用いて四分位数を求めるスクリプト(s2_percentiles_m.py

 

import numpy as np

 

data = [10, 20, 30, 40]

print(data)

 

def MyPercentile( d, p ):

    x = sorted(d)

    n = len(x)

    pos = n * (p / 100.0) + 0.5

    if pos <= 1:

        return x[0]

    elif pos >= n:

        return x[n - 1]

    else:

        i = int(pos)

        v = (pos - i) * x[i] + (i + 1 - pos) * x[i - 1]

        return v

 

Qs = [MyPercentile(data, p) for p in [25, 50, 75]]

print(Qs)

 

リスト2.5を実行すると、以下の出力を得る。

 

[10, 20, 30, 40]

[15.0, 25.0, 35.0]

 

第1四分位数および第2四分位数が、1020および3040の中間地として算出されている。

 

Numpypercentile関数では、いろいろな計算法が用意されている。上の例に対してこれらの計算法による結果を比較するスクリプトをリスト2.5aのように作成してみた。

 

リスト2.5a Percentile計算法の比較(check_percentiles.py

 

import numpy as np

 

a = [10, 20, 30, 40]

methods = ['inverted_cdf', 'averaged_inverted_cdf', 'closest_observation',

           'interpolated_inverted_cdf', 'hazen', 'weibull',

           'linear',      # (default)

           'median_unbiased', 'normal_unbiased', 'lower',

           'higher', 'midpoint', 'nearest']

print('a =', a)

for m in methods:

    Qs = np.percentile(a, [25, 50, 75], method = m)

    print(f'{m:>25s}', Qs)

 

リスト2.5aを実行すると以下の結果を得る。

 

a = [10, 20, 30, 40]

             inverted_cdf [10 20 30]

    averaged_inverted_cdf [15. 25. 35.]

      closest_observation [10 20 30]

interpolated_inverted_cdf [10. 20. 30.]

                    hazen [15. 25. 35.]

                  weibull [12.5 25.  37.5]

                   linear [17.5 25.  32.5]

          median_unbiased [14.16666667 25.         35.83333333]

          normal_unbiased [14.375 25.    35.625]

                    lower [10 20 30]

                   higher [20 30 40]

                 midpoint [15. 25. 35.]

                  nearest [20 30 30]

 

 

 

箱ひげ図

 

本書では、箱ひげ図はヒンジに基づいて説明されている。しかし、Pythonで描かれる箱図は、ヒンジの代わりに四分位数が用いられている。本書の表1.1.1のデータの箱ひげ図を描くスクリプトをリスト2.6のように用意した。

 

リスト2.6 箱ひげ図描画スクリプト(s2_boxplot.py

 

import matplotlib.pyplot as plt

 

data = [

        66, 59, 62, 64, 63, 68, 65, 59, 68, 64,

        65, 51, 67, 64, 83, 59, 61, 62, 57, 72,

        65, 64, 54, 60, 53, 65, 67, 60, 53, 79,

        74, 53, 61, 68, 75, 50, 57, 55, 66, 56,

        55, 61, 70, 71, 49, 69, 70, 80, 73, 72]

 

#       日本語表記の設定

plt.rcParams['font.family'] = ['Yu Gothic', 'Noto Sans CJK JP',

                                   'Hiragino Maru Gothic Pro']

 

plt.boxplot(data, labels = ['テスト'])

plt.xticks(fontsize = 16)

plt.ylabel('点数', fontsize = 16)

plt.show()

 

リスト2.6を実行すると、図2.1の箱ひげ図が描画される。

2.1

 

箱ひげ図の説明は、このウェブサイトでも行っている。

 

 

共分散と相関係数

 

共分散を本書p. 29の式、相関件数をp. 30の式によって算出するスクリプトをリスト2.7のように用意した。

 

リスト2.7 共分散と相関係数の計算スクリプト(s2_fcov_cor.py

 

import matplotlib.pyplot as plt

import numpy as np

 

data = [

        (70, 168), (68, 165), (62, 159), (56, 156), (70, 170),

        (64, 162), (59, 162), (70, 169), (68, 168), (69, 170),

        (67, 168), (63, 166), (58, 163), (74, 170), (65, 168),

        (60, 160), (65, 165), (72, 175), (61, 164), (77, 174),

        (68, 164), (64, 161), (70, 166), (47, 147), (66, 165),

        (68, 170), (73, 174), (74, 172), (63, 164), (83, 182),

        (58, 159), (64, 166), (67, 167), (75, 174), (67, 163),

        (68, 166), (68, 167), (66, 165), (63, 165), (55, 154),

        (61, 163), (60, 160), (62, 164), (62, 160), (59, 160),

        (51, 155), (59, 163), (68, 170), (56, 157), (79, 180)]

 

data = np.array(data)

print(data)

 

mx = np.mean(data.T[0])

my = np.mean(data.T[1])

Cxy = np.mean((data.T[0] - mx) * (data.T[1] - my))

print('共分散 =', Cxy)

 

r = Cxy / \

    ((np.mean((data.T[0] - mx) ** 2) * np.mean((data.T[1] - my) ** 2)) ** 0.5)

print('相関係数 =', r)

 

リスト2.7を実行すると以下の出力を得る。

 

共分散 = 40.867999999999995

相関係数 = 0.9428052005583535

 

リスト2.7Pythonの関数を用いて、リスト2.8のように書き直した。

 

リスト2.8 Pythonの関数による共分散と相関係数の計算(s2_fcov_cor_by_func.py

 

import matplotlib.pyplot as plt

import numpy as np

 

data = [

        (70, 168), (68, 165), (62, 159), (56, 156), (70, 170),

        (64, 162), (59, 162), (70, 169), (68, 168), (69, 170),

        (67, 168), (63, 166), (58, 163), (74, 170), (65, 168),

        (60, 160), (65, 165), (72, 175), (61, 164), (77, 174),

        (68, 164), (64, 161), (70, 166), (47, 147), (66, 165),

        (68, 170), (73, 174), (74, 172), (63, 164), (83, 182),

        (58, 159), (64, 166), (67, 167), (75, 174), (67, 163),

        (68, 166), (68, 167), (66, 165), (63, 165), (55, 154),

        (61, 163), (60, 160), (62, 164), (62, 160), (59, 160),

        (51, 155), (59, 163), (68, 170), (56, 157), (79, 180)]

 

data = np.array(data)

print(data)

 

Cxy = np.cov(data.T, ddof = 0)

print('共分散行列:\n', Cxy)

#print(np.cov(data.T, ddof = 0))

 

r = np.corrcoef(data.T) 

print('相関行列:\n', r)

 

リスト2.8を実行すると、以下の出力を得る。

 

共分散行列:

 [[46.8224 40.868 ]

 [40.868  40.13  ]]

相関行列:

 [[1.        0.9428052]

 [0.9428052 1.       ]]

 

関数の値は、それぞれ共分散行列および相関行列である。

 

 

回帰直線

 

回帰直線の係数を、本書(2.2.5)式により求めるスクリプトをリスト2.9のように作成した。

 

リスト2.9 単回帰直線を求めるスクリプト(s2_regression.py

 

import matplotlib.pyplot as plt

import numpy as np

 

data = [

        (70, 168), (68, 165), (62, 159), (56, 156), (70, 170),

        (64, 162), (59, 162), (70, 169), (68, 168), (69, 170),

        (67, 168), (63, 166), (58, 163), (74, 170), (65, 168),

        (60, 160), (65, 165), (72, 175), (61, 164), (77, 174),

        (68, 164), (64, 161), (70, 166), (47, 147), (66, 165),

        (68, 170), (73, 174), (74, 172), (63, 164), (83, 182),

        (58, 159), (64, 166), (67, 167), (75, 174), (67, 163),

        (68, 166), (68, 167), (66, 165), (63, 165), (55, 154),

        (61, 163), (60, 160), (62, 164), (62, 160), (59, 160),

        (51, 155), (59, 163), (68, 170), (56, 157), (79, 180)]

 

data = np.array(data)

print(data)

 

N = len(data)

print('N =', N)

 

a = (N * np.sum(data.T[0] * data.T[1]) -

     np.sum(data.T[0]) * np.sum(data.T[1])) / \

     (N * np.sum(data.T[0]**2) - np.sum(data.T[0])**2)

b = (np.sum(data.T[0]**2) * np.sum(data.T[1]) -

      np.sum(data.T[0]) * np.sum(data.T[0] * data.T[1])) / \

     (N * np.sum(data.T[0]**2) - np.sum(data.T[0])**2)

 

print('a =', a)

print('b =', b)

 

#       日本語表記の設定

plt.rcParams['font.family'] = ['Yu Gothic', 'Noto Sans CJK JP',

                                   'Hiragino Maru Gothic Pro']

 

plt.plot(data.T[0], data.T[1], 'o')

x_min = np.min(data.T[0])

x_max = np.max(data.T[0])

plt.plot([x_min, x_max], [a*x_min + b, a*x_max + b],

         label = 'a = {0:.3f}\nb = {1:.3f}'.format(a, b))

plt.title('回帰式 a*x + b', fontsize = 24)

plt.legend(fontsize = 12)

plt.show()

 

リスト2.9を実行すると図2.2のグラフが描かれる。

2.2

 

2.2を閉じると、端末には以下の出力が表示されている。

 

N = 50

a = 0.8728300984144342

b = 108.35656437944232

 

 

偏相関係数

 

本書(2.2.13)式に基づいて偏相関係数を求めるスクリプトを、リスト2.10のように作成した。

 

リスト2.10 偏相関係数を求めるスクリプト(s2_partial_corr.py

 

r_xy = float(input('r_xy = '))

r_xz = float(input('r_xz = '))

r_yz = float(input('r_yz = '))

 

r_xy_z = (r_xy - r_xz * r_yz) / \

         (((1 - r_xz**2) * (1 - r_yz**2)) ** 0.5)

 

print('\nr_xy_z =', r_xy_z)

 

リスト2.10を実行すると、まずの値の入力が求められる。

 

r_xy =

 

次のように、例えば「0.56」と設定する。

 

r_xy = 0.56

 

次に、の値の設定が求められる。

 

r_xy = 0.56

r_xz =

 

値を、例えば「0.8」と設定する。

 

r_xy = 0.56

r_xz = 0.8

 

次に、の値の設定が求められる。

 

r_xy = 0.56

r_xz = 0.8

r_yz = 0.7

 

例えば、「0.7」と設定して、Enterキーを押すと計算が始まり、以下のように偏相関係数が表示される。

 

r_xy = 0.56

r_xz = 0.8

r_yz = 0.7

 

r_xy_z = 2.5910386503532426e-16

 

 

順位相関係数

 

Spearmanの順位相関係数とKendallの相関係数をPearsonの相関係数とともに求めるスクリプトをリスト2.11のように用意してみた。

 

リスト2.11 順位相関係数を求めるスクリプト(r2_spearman_corr.py

 

import numpy as np

import scipy.stats as ss

import matplotlib.pyplot as plt

 

data = np.array([[1, 1], [2, 3], [5, 4], [6, 6]])

 

r_Pearson, p_v_pearson = ss.pearsonr(data.T[0], data.T[1])

print('r_Pearson =', r_Pearson, '   p_value =', p_v_pearson)

 

r_Spearman, p_v_spearman = ss.spearmanr(data)

print('r_Spearman =', r_Spearman, '   p_value =', p_v_spearman)

 

r_Kendall, p_v_kendall = ss.kendalltau(data.T[0], data.T[1])

print('r_Kendall =', r_Kendall, '   p_value =', p_v_kendall)

 

plt.plot(data.T[0], data.T[1], 'o',

         label = ('Pearson = {0:.3f}\n' +

                 'Spearman = {1:.3f}\nKendall = {2:.3f}').format(

                 r_Pearson, r_Spearman, r_Kendall))

plt.legend(fontsize = 12)

plt.show()

 

リスト2.11を実行すると、図2.3のグラフが表示される。

2.3

 

2.3のグラフを閉じると、端末には以下の出力が表示されている。

 

r_Pearson = 0.9417419115948377    p_value = 0.058258088405162334

r_Spearman = 1.0    p_value = 0.0

r_Kendall = 1.0    p_value = 0.08333333333333333

 

各相関係数の値と、そのp値が出力されている。

 

 

Up