まずは分布の異なる2種類のdataを作成する。
import numpy as np
np.random.seed(seed=32)
groupA = np.random.normal(100, 20, 100000) #平均100, 標準偏差20の数値をrandomに100000個生成
groupB = np.random.normal(100, 50, 100000) #平均100, 標準偏差50の数値をrandomに100000個生成
print("groupAのsample : {}".format(groupA[0:5]))
print("groupAのsample : {}".format(groupB[0:5]))
groupAのsample : [ 93.02211098 119.67406867 111.61845661 101.40568882 115.55065353]
groupAのsample : [ 122.71129387 134.76068077 88.52182502 92.52887435 107.2470646 ]
平均
まずは平均を見てみると、以下の通り、どちらのグループの数値も平均100付近となる(平均100を指定してるので当たり前)。
meanA, meanB = np.mean(groupA), np.mean(groupB)
print("groupAの平均 = {}, groupBの平均 = {}".format(meanA, meanB))
groupAの平均 = 100.0881959959255, groupBの平均 = 100.13663565328969
しかし、以下のようにhistgramを書いてみると明らかに分布が異なる。groupBはgroupAに比べて山の裾が広く、なだらかな感じ(標準偏差の値が違うので当たり前)。
import seaborn as sns
sns.distplot(groupA, bins=100, label='groupA', kde=False)
sns.distplot(groupB, bins=100, label='groupB', kde=False)
plt.legend()
plt.show()
このように平均だけで比較するとGroupAとGroupBは同等の集団のように思えるが、実はgroupAよりもgroupBの方が値のバラつきが大きいという情報が捨てられている。こういった数字のバラつきを表現する要約統計量が分散や標準偏差である。
※平均も中央値も最頻値も四分位値も要約統計量なので、分散とか標準偏差だけがそう呼ばれているわけではないです。
分散
分散は以下の数式で計算できる
S^2 = \frac{1}{n}{\sum_{i=1}^n(x_i-\bar{x})^2}
つまり (各値 - 平均値)を二乗したものを全て足し合わせて、データ数で割ったもの
である。
各値から平均値をマイナスすることで、平均からどれくらい乖離しているのかを表す指標になりそうだが、それだと負の値になることもあるため、二乗している。
あとはそれを合算し、データ数で割ることで、そのデータのバラつき具合を表現できる。
ちなみに各値-平均値の結果は偏差、それを二乗し、全て足し合わせた値を偏差平方和という。
pythonで書くとこんな感じになる。
groupA[0] - groupA.mean()
s = np.sum((xi - groupA.mean())**2 for xi in groupA)
print(s)
40178555.707617663
var = sum / len(groupA)
print(var)
401.78555707618096
a = ((groupA - groupA.mean())**2).sum()/len(groupA)
b = ((groupB - groupB.mean())**2).sum()/len(groupB)
print("groupAの分散:{:.2f}\ngroupBの分散:{:.2f}".format(a, b))
groupAの分散:401.79
groupBの分散:2496.21
という事で、それぞれの分散がわかり、groupBはAより分散が大きく、数値が平均値付近に集中していない。つまり、ばらついているということがわかる。
標準偏差
Bの方がバラついていることはわかったが、groupAもgroupBも平均100付近の数値の集合だったのが「分散が2496」ですと言われてもよくわからない。そういうときは標準偏差を出すと良い。
S=\sqrt{S^2}
標準偏差は分散の平方根である。分散を計算する際に2乗していたので、ココで平方根をとることにより、元の次元に戻っている。そのため、どの程度数字がばらついているのかを理解しやすくなる。
print("groupAの標準偏差:{:.2f}\ngroupBの標準偏差:{:.2f}".format(math.sqrt(a), math.sqrt(b)))
groupAの標準偏差:20.04
groupBの標準偏差:49.96
最後に
numpyは便利なので、平均も分散も標準偏差も簡単に計算できます。
mean = groupA.mean()
var = groupA.var()
std = groupA.std()
print("平均:{:.2f} 分散:{:.2f} 標準偏差:{:.2f}".format(mean, var, std))
平均:100.09 分散:401.79 標準偏差:20.04