[アルゴリズム×Python]   基本統計量の計算Part3(範囲、分散、標準偏差、変動係数)

アルゴリズムとPythonについて書いていきます。
今回は簡単な計算を関数を使って求めるだけでなく、関数を使わない場合にどうやって求めるかについても書いていきます。

#目次

0.範囲を求める
1.分散を求める
　1-0.母分散を求める
　1-1.不偏分散を求める
2.標準偏差を求める
　2-0.母標準偏差を求める
　2-1.不偏標準偏差を求める
3.変動係数を求める
最後に





#0.範囲を求める

◯範囲(レンジ)は最も単純な**データの広がりを表す量**のことです。
最大値-最小値で簡単に求めることができます。
しかし、**極端な値がデータに含まれている場合**には、範囲がその値によって広がりすぎて必ずしもデータの特性を示すことができるとは限りません。(この問題を解決するのが、分散です)

##最大値と最小値を使った範囲の求め方

◯ある30人のクラスの数学のテストのデータを使って、範囲を考えます。

```.py
test_score = [42, 66, 39, 27, 9, 97, 48, 13, 39, 63, 78, 93, 91, 86, 69, 56, 39, 23, 11, 48, 34, 56, 73, 89, 68, 24, 22, 61, 49, 40]
#最大値と最小値を求める
max_score = max(test_score)
min_score = min(test_score)
#範囲を求める
score_range = max_score-min_score

print('max_score = ',max_score)
print('min_score = ',min_score)
print('score_range = ',score_range)
```
```.py
max_score =  97
min_score =  9
score_range =  88
```




#1.分散を求める

◯分散は、**データのばらつきを示す統計量**として使われるものです。
分散は、要素1つの寄与が小さいので、レンジのように極端な値に左右されません。
ただ、計算過程で2乗をするので**元のデータと単位が異なって**しまいます。(この問題を解決するのが標準偏差です)


◯あるデータのばらつきを知りたい場合に**母集団の分散**が求められれば**それがベスト**です。
ですが、母集団の全要素を把握できず、**母分散が直接求められない**ことは多々あります。そんな時に使うのが、不偏分散です。

|分散の種類|使用目的|特徴|
|:---:|:---:|:---:|
|母分散|母集団の分散を求める|**母集団の要素が全てわかる場合のみ**使用可能|
|標本分散|標本の分散を求める|母分散の推定値にはならない|
|**不偏分散**|標本から母集団の分散を推定する|**母分散の推定値になる**|

※標本分散は実際に使われることはあまりないので今回は扱いません。

[分散はなぜ2乗して求めるのか](https://math.nakaken88.com/textbook/master-variance-definition/)

---

母分散を求める式

```math
S^2 = \frac{1}{n} [(x_1-\bar{x})^2 +(x_2-\bar{x})^2 +...(x_n-\bar{x})^2 ] = \frac{1}{n}\sum_{i=1}^{n}(x_i-\bar{x})^2 
```
---

不偏分散を求める式 

```math
U^2 = \frac{1}{m-1}\sum_{i=1}^{m}(x_i-\bar{x})^2 = \frac{m}{m-1}s^2

```

---

◯標本の大きさがmなのに**不偏分散の自由度がm-1である**のは、不偏分散を求める式の中のm個の観測値がお互いに完全には独立ではなく、**どれか一つの観測値は他のm-1個の独立な観測値と標本平均から求められる**からです。

◯自由度がm-1であることの数学的な説明
[標本分散と不偏分散の関係について](https://stats.biopapyrus.jp/stats/var.html)
 

◯母分散と不偏分散の式を比べた時、分母だけがこのように異なるのは一見変な感じがするかもしれません。
しかし、**母集団の大きさｎがかなり大きく**、また**標本の大きさmがnと同等までに大きくなった極限**では、不偏分散が母分散にほぼ一致し、**母分散の良い推定値となる**ことが証明されています。

---


##1-0.母分散を求める

◯母分散とは、母集団の分散のことです。母集団の要素が全てわかる場合に使用します。

◯母分散は各データの平均からのずれ(偏差)の 2 乗を合計して、データ数で割ったものです。つまり、**データの要素が平均からずれているほど母分散は大きな値**になります。

---

###pvariance()関数を使った母分散の求め方

◯あるクラスの数学のテストの点数データを母集団として、母分散を求めます。つまり、このクラスのテストの点数のばらつき度合いを求めます。

```.py
import statistics
#テストの点数のリスト
test_score = [42, 66, 39, 27, 9, 97, 48, 13, 39, 63, 78, 93, 91, 86, 69, 56, 39, 23, 11, 48, 34, 56, 73, 89, 68, 24, 22, 61, 49, 40]

population_variance = statistics.pvariance(test_score)
print('population_variance =',population_variance)
```
```.py
population_variance = 638.6455555555556
```

---

###偏差を使った母分散の求め方
母分散を求める式

```math
S^2 = \frac{1}{n} [(x_1-\bar{x})^2 +(x_2-\bar{x})^2 +...(x_n-\bar{x})^2 ] = \frac{1}{n}\sum_{i=1}^{n}(x_i-\bar{x})^2 
```

◯**(データ値)-(平均値)**のことを**偏差(=deviation)**といいます。上の式では、偏差を求め、それを2乗したものを合計し、要素数で割っています。

```.py
import statistics

test_score = [42, 66, 39, 27, 9, 97, 48, 13, 39, 63, 78, 93, 91, 86, 69, 56, 39, 23, 11, 48, 34, 56, 73, 89, 68, 24, 22, 61, 49, 40]
#リストの要素数を求める
n = len(test_score)
#テストの点数の平均点を求める
score_mean  = statistics.mean(test_score)
#偏差の2乗のリストをつくる
squared_deviation_list = [(score-score_mean)**2 for score in test_score]
#母分散 = squared_deviation_listの総和/要素数
population_variance = sum(squared_deviation_list)/n

print('population_variance = ',population_variance)
```
```.py
population_variance =  638.6455555555556
```


---


###平均を使った母分散の求め方

◯母分散は以下のような形にも変形できます。これを使って母分散を求めていきます。

```math
S^2 = \frac{1}{n} (x_1^2+x_2^2+...+x_n^2)-\bar{x}^2 = \frac{1}{n}\sum_{i=1}^{n}x_i^2-\bar{x}^2 
```
①要素数を求めておく
②平均値を求めておく
③要素を2乗してリスト化する
④要素を2乗したリストの総和を求めてこれを要素数で割る
⑤そこから平均値の2乗を引く

```.py
#テストの点数のリスト
import statistics

test_score = [42, 66, 39, 27, 9, 97, 48, 13, 39, 63, 78, 93, 91, 86, 69, 56, 39, 23, 11, 48, 34, 56, 73, 89, 68, 24, 22, 61, 49, 40]
#要素数を求める
n = len(test_score)
#テストの平均値を求める
score_mean = statistics.mean(test_score)
#リストの各要素を2乗する
squared_test_score = [score**2 for score in test_score]
#「各要素の2乗の総和を要素数でわったもの」-「テストの平均値の2乗」
population_variance = sum(squared_test_score)/n - (score_mean)**2
print('score_mean = ',score_mean)
print('population_variance = ',population_variance)
```
```.py
score_mean =  51.766666666666666
population_variance =  638.6455555555558
```




----------------------------------------------------------------------


#1-1.不偏分散を求める

◯不偏分散は、標本から母集団の分散を推定する時に使います。
母集団の全要素を把握せずとも母集団の性質を把握できる便利な計算です。

不偏分散を求める式 

```math
U^2 = \frac{1}{m-1}\sum_{i=1}^{m}(x_i-\bar{x})^2 = \frac{m}{m-1}s^2
```


 
---


###variance()関数を使った不偏分散の求め方



```.py
import statistics

#テストの点数の標本(サンプル)
test_score_sample = [27, 22, 22, 73, 56, 61, 61, 22, 27, 63, 61, 22, 27, 61, 22, 61, 73, 61, 27, 73]

#不偏分散(=unbiased_distribution)を、標本test_score_sampleから求める
unbiased_distribution = statistics.variance(test_score_sample)
print('unbiased_distribution =',unbiased_distribution)
```
```.py
unbiased_distribution = 434.2
```

---

###pvariance()関数を使った不偏分散の求め方

◯母集団の平均がわかっている場合にのみ使用可能です。

◯母集団の平均がわからない場合に、サンプルデータでこの関数を実行すると、n自由度の標本分散が得られます。つまり、母分散の不偏推定値にはなりません。

```.py
import statistics

#母集団の平均
score_mean = 51.766666666666666

#テストの点数の標本(サンプル)
test_score_sample = [27, 22, 22, 73, 56, 61, 61, 22, 27, 63, 61, 22, 27, 61, 22, 61, 73, 61, 27, 73]

#不偏分散(=unbiased_distribution)を、標本test_score_sampleから求める
#母集団の平均は第2引数で指定する
unbiased_distribution = statistics.pvariance(test_score_sample,score_mean)
print('unbiased_distribution =',unbiased_distribution)
```
```.py
unbiased_distribution = 412.49
```
















---

###偏差を使った不偏分散の求め方

◯下の式のように偏差の2乗の総和を、サンプルサイズ-1で割って不偏分散を求めます。

不偏分散を求める式

```math
u^2 = \frac{1}{m-1}\sum_{i=1}^{m}(x_i-\bar{x})^2 = \frac{m}{m-1}s^2
```

①サンプルサイズを求めておく
②偏差を求めるために平均値を求めておく
③**偏差の2乗**を要素に持つリストをつくる
④このリストの総和を、m-1(=サンプルサイズ-1)でわる

```.py
import statistics

#テストの点数の標本(サンプル)
test_score_sample = [27, 22, 22, 73, 56, 61, 61, 22, 27, 63, 61, 22, 27, 61, 22, 61, 73, 61, 27, 73]

#サンプルサイズを求めておく
m = len(test_score_sample)
#偏差を求めるためにサンプルの平均を求める
score_mean = statistics.mean(test_score_sample)
#偏差(=score-score_mean)の2乗のリストをつくる
squared_deviation_list = [(score-score_mean)**2 for score in test_score_sample]

#母分散 = squared_deviation_listの総和/サンプルサイズ-1
unbiased_distribution = sum(squared_deviation_list)/m-1

print('unbiased_distribution = ',unbiased_distribution)
```
```.py
unbiased_distribution =  411.49000000000007
```














#2.標準偏差を求める

◯標準偏差は母標準偏差と、不偏標準偏差があります。

◯母標準偏差は母分散の平方根をとってデータと単位を揃え、データの拡がりをわかりやすくしたものです。

◯不偏標準偏差は、母標準偏差の不偏推定量となるものです。

##2-0.母標準偏差を求める

◯母標準偏差は母分散の平方根をとったものです。


###pstdev()関数を使って求める

```.py
import statistics

#テストの点数(母集団)
test_score = [42, 66, 39, 27, 9, 97, 48, 13, 39, 63, 78, 93, 91, 86, 69, 56, 39, 23, 11, 48, 34, 56, 73, 89, 68, 24, 22, 61, 49, 40]

population_standard_deviation = statistics.pstdev(test_score)
print('population_standard_deviation =',population_standard_deviation)
```
```.py
population_standard_deviation = 25.27143754430198
```

---

###母分散を使って求める

◯母分散の平方根をとったものが母標準偏差なので、それを利用する。

①母分散をpvariance()関数で求める
②母分散の平方根をとる

```.py
import statistics
import sympy

test_score = [42, 66, 39, 27, 9, 97, 48, 13, 39, 63, 78, 93, 91, 86, 69, 56, 39, 23, 11, 48, 34, 56, 73, 89, 68, 24, 22, 61, 49, 40]
#母分散を求める
population_variance = statistics.pvariance(test_score)
#母分散の平方根をとる
#root(ルートの中身,~乗根)
population_standard_deviation = sympy.root(population_variance,2)

print('population_variance = ',population_variance)
print('population_standard_deviation = ',population_standard_deviation)
```
```.py
population_variance =  638.6455555555556
population_standard_deviation =  25.2714375443020
```

---

###偏差の2乗平均を使って求める

◯母標準偏差は、**偏差を2乗平均をしたもの**と同等です。

⓪偏差を求めるために、データの平均値を求める
①**偏差**を要素に持つリストをつくる。
②**偏差の2乗**を要素に持つリストをつくる。(各要素の2乗)
③このリストの平均値を求める。
④平均値の平方根をとる

◯二乗平均は、**平均したい数値を2乗して合計し要素数ｎで割った値を平方根して算出します**。輸送機関の時刻表に対する到着時間との差分を算出したいときなどに利用します。

◯2分の遅れも2分早く到着することも、時刻の乱れがあることに違いはありません。しかし、**プラスマイナスがあるまま算術平均をする**とその**誤差を相殺**してしまいます。
なので、**2乗することでマイナスをなくして**計算をおこないます。

-----------------------------------------------------------------------------

```.py
import sympy
import statistics

#テストの点数のデータ(母集団)
test_score = [42, 66, 39, 27, 9, 97, 48, 13, 39, 63, 78, 93, 91, 86, 69, 56, 39, 23, 11, 48, 34, 56, 73, 89, 68, 24, 22, 61, 49, 40]
#偏差を求めるために母集団の平均値を求める
score_mean = statistics.mean(test_score)

#偏差(点数と平均の差分)のリストをつくり、このリストについて２乗平均を求めていく
deviation_list = [score-score_mean for score in test_score]

#リストの各要素を2乗して新しいリストsquared_test_scoreをつくる
squared_deviation_list = [i**2 for i in deviation_list]
#squared_deviation_listの平均値を求める(総和/サンプルサイズ)
mean_square = sum(squared_deviation_list)/len(squared_deviation_list)
#mean_squareの平方根をとる
root_mean_square = sympy.root(mean_square,2)

print('RMS = population standard deviation = ',root_mean_square)
```


```.py
#偏差の2乗平均 = 母標準偏差 = 25.2714375443020
RMS = population standard deviation = 25.2714375443020
```





------------------------------------------------------------------------

##2-1.不偏標準偏差を求める

◯**母標準偏差の不偏推定量のこと**です。

◯また、不偏分散の平方根そのものではなく、**不偏分散の平方根を補正したもの**が不偏標準偏差です。

◯不偏分散は母分散の不偏推定量なので、不偏分散の平方根が不偏標準偏差であり、母偏標準偏差の不偏推定量であると思われることが多々あります。
しかし、**不偏分散の平方根は不偏標準偏差ではありません。**

母標準偏差の不偏推定量としての不偏標準偏差 Us は、不偏分散U^2の平方根を、係数 C4 で除した値です。

```math
U^2 = \frac{1}{m-1}\sum_{i=1}^{m}(x_i-\bar{x})^2 = \frac{m}{m-1}s^2
```
```math
C_4 = \frac{\sqrt{\frac{2}{n-1}} \Gamma(\frac{2}{n})}{\Gamma(\frac{n-1}{2})}
```


不偏標準偏差の式

```math
U_s = \frac{\sqrt{U^2}}{C_4}
```

[水増し係数と割引き係数：不偏標準偏差と管理図係数](https://biolab.sakura.ne.jp/mizumashi-waribiki-keisu.html)
[不偏分散の平方根は標準偏差の不偏推定量か](https://bellcurve.jp/statistics/blog/13645.html)
[不偏標準偏差とは？：統計検定を理解せずに使っている人のために](https://biolab.sakura.ne.jp/unbiased-standard-deviation.html)

###stdev()関数を使って不偏標準偏差を求める

```.py
import statistics

#テストの点数の標本(サンプル)
test_score_sample = [27, 22, 22, 73, 56, 61, 61, 22, 27, 63, 61, 22, 27, 61, 22, 61, 73, 61, 27, 73]

unbiased_standard_deviation = statistics.stdev(test_score_sample)
print('unbiased_standard_deviation = ',unbiased_standard_deviation)
```
```.py
unbiased_standard_deviation =  20.837466256721328
```






#3.変動係数を求める

◯変動係数とは標準偏差を平均値で割った値のことです。

◯単位の異なるデータのばらつきや、平均値に対するデータとばらつきの関係を相対的に評価する際に用いる単位を持たない（＝無次元の）数値です。変動係数はCVで表されることがあります。

変動係数(Coefficient of Variation)を求める式

```math
CV = \frac{S}{\bar{x}}
```


##母標準偏差と平均値を使った変動係数の求め方

```.py
import statistics

#人間とネズミの体重をそれぞれ10回測ったデータ
#単位はkgで揃えている
human_data = [75,77,75,76,78,76,75,76,77,75]
mouse_data = [0.04,0.05,0.02,0.03,0.02,0.03,0.05,0.06,0.07,0.03]

#pstdev()関数を使って、それぞれの母標準偏差を求める
human_pstdev = statistics.pstdev(human_data)
mouse_pstdev = statistics.pstdev(mouse_data)

#mean()関数を使ってそれぞれの平均値を求める
human_mean = statistics.mean(human_data)
mouse_mean = statistics.mean(mouse_data)

#変動係数を求める
#母標準偏差と平均値の比率を求める
human_cv = human_pstdev/adult_mean
mouse_cv = mouse_pstdev/mouse_mean

print('human_pstdev = ',human_pstdev)
print('mouse_pstdev = ',mouse_pstdev)
print('human_cv = ',human_cv)
print('mouse_cv = ',mouse_cv)
```
```.py
#母標準偏差は人の方が大きい(ばらつきを表す数値が大きい)
#kg単位でのばらつきを表す
human_pstdev =  1.0
mouse_pstdev =  0.0161245154965971

#変動係数はマウスの方が大きい(ばらつきの度合いが大きい)
human_cv =  0.013106159895150722
mouse_cv =  0.40311288741492746
```















#最後に
読んでいただきありがとうございました。
間違いや改善点などのご指摘いただけると幸いです。
よろしくお願い致します。