ハンバーガー統計学にようこそ!の第1章をPythonでやってみたもの。
準備
# -*- coding:utf-8 -*- import pandas as pd import numpy as np import matplotlib.pyplot as plt
1.1 ポテトの長さの平均は
# ワクワクバーガー waku = pd.Series( [3.5, 4.2, 4.9, 4.6, 2.8, 5.6, 4.2, 4.9, 4.4, 3.7, 3.8, 4.0, 5.2, 3.9, 5.6, 5.3, 5.0, 4.7, 4.0, 3.1, 5.8, 3.6, 6.0, 4.2, 5.7, 3.9, 4.7, 5.3, 5.5, 4.7, 6.4, 3.8, 3.9, 4.2, 5.1, 5.1, 4.1, 3.6, 4.2, 5.0, 4.2, 5.2, 5.3, 6.4, 4.4, 3.6, 3.7, 4.2, 4.8] ) # モグモグバーガー mogu = pd.Series( [4.5, 4.2, 3.9, 6.6, 0.8, 5.6, 3.2, 6.9, 4.4, 4.7, 3.8, 3.0, 3.2, 4.9, 7.6, 3.3, 7.0, 3.7, 3.0, 4.1, 5.8, 4.6, 4.0, 2.2, 7.7, 3.9, 6.7, 3.3, 7.5, 2.7, 5.4, 5.8, 5.9, 3.2, 5.1, 3.1, 6.1, 4.6, 2.2, 4.0, 6.4, 5.2, 3.3, 6.4, 6.4, 2.6, 2.6, 5.2, 5.8] ) # 集計 # 総和と平均を求める waku.sum() # 224.0 waku.mean() # 4.5714285714285712 mogu.sum() # 226.10000000000002 mogu.mean() # 4.6142857142857148
箱ひげ図はDataFrameにしてから描画すると簡単。
df = pd.DataFrame({"waku":waku, "mogu":mogu}) df.boxplot(grid=False) plt.show()
1.2 度数分布
度数分布はpandas.cut
で分割し、これに基づいてpandas.groupby
で元データを分割、グループごとにcount
を適用するという手順をとることで得られる(cf. pandas で年齢階級をつくる - Qiita)。
waku.groupby(pd.cut(waku, np.arange(0, 9, 1))).count()
(0, 1] 0 (1, 2] 0 (2, 3] 1 (3, 4] 14 (4, 5] 19 (5, 6] 13 (6, 7] 2 (7, 8] 0 dtype: int64
mogu.groupby(pd.cut(mogu, np.arange(0, 9, 1))).count()
(0, 1] 1 (1, 2] 0 (2, 3] 7 (3, 4] 13 (4, 5] 8 (5, 6] 9 (6, 7] 8 (7, 8] 3 dtype: int64
ヒストグラムの方が作るのは簡単な印象。
df.hist(bins=np.arange(0,9,1), sharey=True, # y軸を揃える grid=False, # グリッド非表示 layout=(2,1)) # 2行1列に並べる plt.show()
1.4 分散と標準偏差
df.var(ddof=0) # 分散
mogu 2.584898 waku 0.680816 dtype: float64
df.std(ddof=0) # 標準偏差
mogu 1.607762 waku 0.825116 dtype: float64
ddof
はDelta Degrees of Freedom
で、自由度はサンプルサイズをNとしてN - ddof
として指定される。Pandasの場合はデフォルトが1なので、何も指定しないと不偏分散およびそれに基づく標準偏差が計算される。今回はテキストに合わせるためにあえて0を指定している。
なお、numpy.var
およびnumpy.std
も分散および標準偏差を計算するメソッドであり、ddof
という同名の引数が用意されているが、なんとこちらはデフォルトが0である。
1.9 通過テスト
df = pd.DataFrame({ "桜組" : [78, 62, 81, 59, 72, 68, 75, 65, 80, 60, 78, 62, 70], "桃組" : [70, 72, 68, 75, 65, 71, 69, 76, 64, 80, 60, 73, 67], "柳組" : [57, 59, 55, 62, 52, 58, 56, 63, 51, 67, 47, 60, 54] })
平均、分散、標準偏差はdf.mean()
, df.var()
, df.std()
でそれぞれ計算できるが、df.describe()
を使うとデータ数、平均、標準偏差といわゆる五数要約(最大値、75%点、中央値、25%点、最小値)を確認できる。
df.describe()
柳組 桃組 桜組 count 13.000000 13.000000 13.000000 mean 57.000000 70.000000 70.000000 std 5.400617 5.400617 7.937254 min 47.000000 60.000000 59.000000 25% 54.000000 67.000000 62.000000 50% 57.000000 70.000000 70.000000 75% 60.000000 73.000000 78.000000 max 67.000000 80.000000 81.000000
また、scipy.stats.describe()
ではデータ数、最大値、最小値、平均、分散、歪度、尖度を確認でき、ddof
で自由度を指定できる。
import scipy as sp sp.stats.describe(df)
DescribeResult(nobs=13, minmax=(array([47, 60, 59]), array([67, 80, 81])), mean=array([ 57., 70., 70.]), variance=array([ 29.16666667, 29.16666667, 63. ]), skewness=array([ 0., 0., 0.]), kurtosis=array([-0.44902857, -0.44902857, -1.47721928]))
ついでに日本語ラベル付きのヒストグラムでも描いてみようと思って日本語表示に結構手間取った。seabornの設定でフォントを指定するとmatplotlibの設定もまとめて上書きされるので楽っぽい(cf.matplotlib と Seaborn の軸の日本語設定 - Qiita)。
import seaborn as sns sns.set(font='Ricty') # Rictyは別途インストールしたフォント df.hist() plt.show()
seabornでも描いてみよう。
for i in df.columns: ax = sns.distplot(df[i], label=i, bins = 4) ax.legend() plt.show()
適当にやっても綺麗に出力される印象(cf.python - Two seaborn distplots one same axis - Stack Overflow)。