2019年5月2日木曜日

[Statistics] III データ分析 記述統計:1変量データ編

Pythonで学ぶあたらしい統計学の教科書のまとめやコードを実行してみた際のメモです.

統計量の計算などの,基本的なデータ分析に使う関数は Scipy というパッケージに入っています.
>>> import numpy as np
>>> import scipy as sp
ここでは,NumpyとScipyパッケージを読み込んでいます.

1変量データの管理
1変量データ:1種類しかないデータ
1変量データを扱う場合は,Numpyアレイを使うと簡単です.以下では,fish_data という変数に10個のデータを格納しています.
>>> fish_data = np.array([2, 3, 3, 4, 4, 4, 4, 5, 5, 6])
>>> fish_data
array([2, 3, 3, 4, 4, 4, 4, 5, 5, 6])

合計とサンプルサイズ
合計値を計算する場合には,Scipyのsum関数を用います.
>>> sp.sum(fish_data)
40

合計値を求めるだけであれば,ScipyでなくてもNumpy(np.sum)やPythonの標準関数(sum)でも同じ結果となります.

>>> np.sum(fish_data)
40
>>> sum(fish_data)
40

ただし,同じ関数名であってもパッケージによって挙動が異なることが稀にあるので,データ分析に関わる基本的な関数はScipyの関数を用いることにします.



サンプルサイズを求めるには(例外的に)Pythonの標準関数を用います.
>>> len(fish_data)
10

平均値(期待値)
平均値を計算してみます.平均値の計算式は以下のようになります.
$\mu = \cfrac{1}{N} \sum_{i = 1}^{N} x_{i}$
Pythonのコードは以下のようになります.
>>> N = len(fish_data)
>>> sum_value = sp.sum(fish_data)
>>> mu = sum_value / N
>>> mu
4.0

Scipyのmean関数を使うと平均値を簡単に計算できます.
>>> sp.mean(fish_data)
4.0

標本分散
分散はデータが平均値からどれだけ離れているかを表す指標です.計算式は以下のようになります.
$\sigma^{2} = \cfrac{1}{N} \sum_{i = 1}^{N} ( x_{i} - \mu)^{2}$
Pythonによるコード(総和にはScipyを使用していますが...)は以下のようになります.

>>> sigma_2_sample = sp.sum((fish_data - mu) ** 2) / N
>>> sigma_2_sample
1.2

偏差平方和を計算する sp.sum((fish_data - mu) ** 2) に関して,以下に説明します.

まずはfish_dataの確認を行います.これは,上記の式では$x_{i}$に相当します.

>>> fish_data
array([2, 3, 3, 4, 4, 4, 4, 5, 5, 6])


fish_data - mu とすると,$x_{i} - \mu$の一覧が得られます.
>>> fish_data - mu
array([-2., -1., -1.,  0.,  0.,  0.,  0.,  1.,  1.,  2.])

(fish_data - mu) ** 2で全ての値が二乗され,$( x_{i} - \mu)^{2}$の一覧が得られます.
>>> (fish_data - mu) ** 2
array([4., 1., 1., 0., 0., 0., 0., 1., 1., 4.])

最後にこれらの値を合計します.
>>> sp.sum((fish_data - mu) ** 2)

12.0

これらの合計をサンプルサイズ(10)で割れば分散の計算になります.

Scipyのvar関数を用いて計算すると以下のように簡単に計算できます.

>>> sp.var(fish_data, ddof = 0)
1.2

ここで,doff = 0 と指定(標本分散という指定)することに注意が必要です.

不偏分散
標本分散は,標本平均を使ってさらに分散を計算した値です.この値は分散を過小に見積もってしまうというバイアスがあるので,このバイアスをなくしたものが不偏分散です.不偏分散の計算式は以下のようになります.
$\sigma^{2} = \cfrac{1}{N-1} \sum_{i = 1}^{N} ( x_{I} - \mu)^{2}$
Pythonによるコード(総和にはPythonを利用...)は以下のようになります.
>>> sigma_2 = sp.sum((fish_data - mu) ** 2) / (N - 1)
>>> sigma_2
1.3333333333333333

Scipyのvar 関数のdoff = 1(不偏分散という指定)と指定することで不偏分散を計算できます.
>>> sp.var(fish_data, ddof = 1)
1.3333333333333333

標準偏差
分散の平方根を取ったものが標準偏差です.標準偏差の計算式は以下のようになります.
$\sigma = \sqrt{sigma^{2}} = \sqrt{\cfrac{1}{N-1} \sum_{i = 1}^{N} (x_{i} - \mu)^{2}}$
Pythonによるコード(総和にはPythonを利用...)は以下のようになります.
>>> sigma = sp.sqrt(sigma_2)
>>> sigma
1.1547005383792515

Scipyのstd関数を使うと以下のように簡単に計算できます.不偏分散の平方根を使う場合は ddof = 1 と指定する必要があります(標本分散を使う際にはddof = 0と指定).
>>> sp.std(fish_data, ddof = 1)
1.1547005383792515
>>> sp.std(fish_data, ddof = 0)
1.0954451150103321

標準化
標準化:データの平均を0に,標準偏差を1に変換すること
平均値は,大きな変数,もしくは小さな変数が入り混じっていると特徴が掴みにくいため,標準化してからデータを比較することがあります.

データの平均値を0にするには,全てのデータから一律に平均値を引けば良いことになります.
>>> fish_data - mu
array([-2., -1., -1.,  0.,  0.,  0.,  0.,  1.,  1.,  2.])
この操作で,fish_data - mu の平均は0になっています.

Scipyのmean関数を用いてfish_data - muの平均を求めると以下のようになります.
>>> sp.mean(fish_data - mu)
0.0

同様に,データの標準偏差(あるいは分散)を1にする場合は,データを一律に標準偏差で割れば良いことになります.
>>> fish_data / sigma
array([1.73205081, 2.59807621, 2.59807621, 3.46410162, 3.46410162,
       3.46410162, 3.46410162, 4.33012702, 4.33012702, 5.19615242])

fish_data / sigma の標準偏差が1になっていることを,Scipyのstd関数を用いて確認するには,以下のようにします.
>>> sp.std(fish_data / sigma, ddof = 1)
1.0

これらの両方の変換を併せると,平均0,標準偏差(分散)1にすることができます.
>>> standard = (fish_data - mu) / sigma
>>> standard
array([-1.73205081, -0.8660254 , -0.8660254 ,  0.        ,  0.        ,
        0.        ,  0.        ,  0.8660254 ,  0.8660254 ,  1.73205081])

平均が0になっていることをScipyのmean関数を用いて確認します.
>>> sp.mean(standard)
2.2204460492503132e-17

標準偏差が1になっていることをScipyのstd関数を用いて確認します.
>>> sp.std(standard, ddof = 1)
1.0

その他の統計量
統計量の中で平均と分散は重要ですが,これら以外の統計量も存在します.以下にそれらを求めてみます.

最大値はScipyのamax関数を用いて求めます.
>>> sp.amax(fish_data)
6
最小値はScipyのamin関数を用いて求めます.
>>> sp.amin(fish_data)
2
中央値(データを昇順に並べたときに,ちょうど真ん中にくる数値のこと)は,Scipyのmedian関数を用いて求めます.
>>> sp.median(fish_data)
4.0

例としている fish_data では,平均値と中央値は同じになります.これは左右対称のデータの場合は,これらの2つの値は(大体)同じになることを示しています.当然,左右非対称の場合は異なる値になります.
その例として,以下のデータセットを考えます.fish_data と違って,最後に100という大きな値があります.この値に引きずられて平均値(Scipyのmean関数で求める)は先の例に比べて大きくなります.中央値(Scipyのmedian関数で求める)はデータの数が変わっていないので変化はありません.
>>> fish_data_2 = np.array([2, 3, 3, 4, 4, 4, 4, 5, 5, 100])
>>> sp.mean(fish_data_2)
13.4
>>> sp.median(fish_data_2)
4.0
100といった,他と大きくズレたデータを外れ値と言います.平均値は外れ値の影響を大きく受けますが,中央値は大して変化しない傾向があります.このような特徴があるため,中央値の方が外れ値に頑健であるということができます.

Scipyの中のstatsを読み込むことで,Scipyの中でも特に統計分析に特化した関数を使うことができるようになります.
>>> from scipy import stats

statsの中のscoreatpercentile関数を用いて,四分位点を求めてみます.
四分位点:データを昇順に並び替えた時に,下から25%,75%にくる値のこと.
わかりやすくするために,以下の新しいデータで実行してみます.
>>> fish_data_3 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])

昇順に並べて,小さいモノから順に数えて25%にくる値は以下のようになります.
>>> stats.scoreatpercentile(fish_data_3, 25)
3.0

小さいモノから順に数えて75%にくる値は以下のようになります.

>>> stats.scoreatpercentile(fish_data_3, 75)
7.0


上記の事柄をJupiter Notebookで実行した結果はGitHubで公開しています.
Pythonではなく,Juliaで実装してみた例もGitHubで公開しています.

0 件のコメント :

コメントを投稿