データ分析 python 2群間の代表値の検定:スチューデントのt検定(ウェルチのt検定)
以前まとめた2群間の代表値の検定について、具体的な手法を簡単にまとめてみます。
python + google colaboratory で 実行しています。
テーマ
あるカフェチェーンの経営者が、
2種類の新メニュー(メニューAとメニューB)の人気度を比較するため、
異なる10店舗ずつにメニューAとメニューBを導入しました。
1ヶ月後、それぞれのメニューの売上を集計したところ、
メニューAを導入した店舗とメニューBを導入した店舗で平均売上に差があるように見えました。
この差は統計的に有意と言えるでしょうか?
使用したデータ
カフェチェーンの売上データを想定しています。
index | 店舗番号 | メニューA売上 | メニューB売上 |
---|---|---|---|
0 | 1 | 524.8357076505616 | 496.8291153593769 |
1 | 2 | 493.0867849414408 | 496.7135123214872 |
2 | 3 | 532.3844269050346 | 532.0981135783018 |
3 | 4 | 576.1514928204012 | 424.3359877671101 |
4 | 5 | 488.2923312638332 | 433.75410837434833 |
5 | 6 | 488.293152152541 | 491.88562353795135 |
6 | 7 | 578.9606407753696 | 469.3584439832788 |
7 | 8 | 538.3717364576454 | 535.7123666297637 |
8 | 9 | 476.5262807032524 | 474.5987962239395 |
9 | 10 | 527.1280021792983 | 449.3848149332354 |
前準備
グラフに日本語ラベルを表示できるように japanize-matplotlib をインストールします。
!pip install -q japanize-matplotlib
必要のライブラリをインポートして、使用するデータを読み込んでおきます。
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib
import seaborn as sns
from scipy import stats
# データ読込
df = pd.read_csv('/content/drive/MyDrive/cofee_sales.csv')
df
メニューA売上データとメニューB売上データの代表値を確認
メニューA売上データとメニューB売上データの平均値を確認する
df.mean()
メニューA売上データとメニューB売上データの中央値を確認する
df.median()
平均値にも中央値にも、メニューAとメニューBの売上に差があります。
この差は標本集団だけの差なのか、母集団でも意味ある差なのかを検定していきます。
使用する検定を決定する
1.正規性を視覚的に確認する
まずは使用する検定を特定するために、データが正規性に従っているかを確認します。
メニューA売上データとメニューB売上データの値をヒストグラムで可視化して正規性を確認してみます。
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
sns.histplot(df['メニューA売上'], kde=True)
plt.subplot(1, 2, 2)
sns.histplot(df['メニューB売上'], kde=True)
2.正規性を統計的に確認
視覚だけでなく統計的にも正規分布に従っているかを確認します。
正規性を確認する代表的な検定方法には下記のような検定があります。
- シャピロ・ウィルク検定(S-W検定)
- 小さいデータセットに適しています
- scipy の shapiroメソッドを使用
- コルモゴロフ・スミルノフ検定(K-S検定)
- 広く使われています
- scipy の kstestメソッドを使用
- Anderson-Darling検定
- シャピロ・ウィルク検定よりも詳細な正規性の確認ができます。
- Q-Qプロット
- 視覚的にデータの正規性を確認するのに便利です。
今回はデータセットが小さいので シャピロ・ウィルク検定 を使用して正規性を検定します。
シャピロ・ウィルク検定 は scipy の shapiroメソッドを使用します。
帰無仮説:正規分布である
対立仮説:正規分布でない
P値が0.05より小さい場合、帰無仮説を棄却し、データは正規分布に従っていないと判断します。
from scipy import stats
stats.shapiro(データ)
ちなみに、データセットが多い場合は コルモゴロフ・スミルノフ検定 を使用します
コルモゴロフ・スミルノフ検定 は scipy の kstestメソッドを使用します。
正規性を検定する際は kstest メソッドの第二引数に'"norm"'を指定します。
from scipy import stats
stats.kstest(データ, "norm")
正規性を検定する
それでは、メニューA売上 と メニューB売上 の それぞれのデータを検定してみます。
メニューA売上データの正規性を検定する
stats.shapiro(df['メニューA売上'])
ShapiroResult(statistic=0.9076583366928279, pvalue=0.2652904769244879)
P値(pvalue)=0.265 と 優位水準を0.05を上回っていますので、帰無仮説を棄却できず
メニューA売上データは正規分布に従っていると判断します。
メニューA売上データの正規性を検定する
stats.shapiro(df['メニューB売上'])
ShapiroResult(statistic=0.9507256148338621, pvalue=0.6770909909669156)
P値(pvalue)=0.677 と 優位水準を0.05を上回っていますので、帰無仮説を棄却できず
メニューB売上データも正規分布に従っていると判断します。
3.分散を確認する
メニューA売上データ と メニューB売上データ の両方が、正規分布に従うので「パラメトリック検定」で、かつ 今回は、比較の対処が異なるので「対応なし」データになります。
対応なしデータの場合、データのばらつきが等しいか(=等分散)、ばらつきが異なるのか(=不等分散)を確認します。
分散を検定するには scipy の bartlett メソッドを使用します。
帰無仮説:各グループの分散は等しい
対立仮説:各グループの分散は等しくない
P値が0.05より小さい場合、帰無仮説を棄却し、各グループの分散は等しくないと判断します。
from scipy import stats
stats.bartlett(データ1, データ2)
それでは メニューA売上 と メニューB売上 の 分散性を検定します。
from scipy import stats
stats.bartlett(df['メニューA売上'], df['メニューB売上'])
BartlettResult(statistic=0.016297583124879254, pvalue=0.8984164732373576)
P値(pvalue)=0.898 と 優位水準を0.05を上回っていますので、帰無仮説を棄却できず
メニューA売上とメニューB売上の分散は等しいと判断します。
4.使用する検定
メニューA売上データ と メニューB売上データ の両方が、正規表現に従うので「パラメトリック検定」になります。
また今回は、比較の対処が異なるので「対応なし」データになり、各グループのデータは「等分散」となります。
よって、今回使う検定は「スチューデントのt検定」となります。
スチューデントのt検定は scipy の ttest_ind メソッドを使用します。
ttest_ind は「independent(独立)」を意味しています。
等分散の場合は equal_var パラメータに True を指定します。
不等分散の場合は equal_var パラメータに False を指定します。
使い方
from scipy import stats
stats.ttest_ind(df['メニューA売上'], df['メニューB売上'], equal_var=True)
検定を行う
それでは実際に検定を行います。
1.仮説立て
- 帰無仮説:2群間の平均値に有意な差はない
- 対立仮説:2群間の平均値に有意な差はある
2.優位水準
- 5%
3.判定
stats.ttest_ind(df['メニューA売上データ'], df['メニューB売上データ'], equal_var=True)
出力結果
TtestResult(statistic=2.5366212217624033, pvalue=0.02066949898514672, df=18.0)
P値(pvalue)は「0.02」と優位水準より小さいので
有意水準 > P値 となり 帰無仮説を棄却し、対立仮説を採用します。
4.結論
メニューA売上データ と メニューB売上データの平均の差には母集団においても有意な差であったと判断できます。
以上で、今回の検定は終了です。
Discussion