LoginSignup
1
4

More than 5 years have passed since last update.

アンケート調査で「全体の比率」と「一部の比率」の差の検定(有意差検定)を行うプログラム

Last updated at Posted at 2019-01-29

はじめに

アンケート調査をしたことはありますか。
そして「そのアンケート結果って有意に差があるの?」と言われたことはありますか。

問題

例えばランダムに集めてきた男女100人にアンケートを取って、
そのうち30人が「このサービスに満足した」と答えたとしましょう。
全体のサービス満足率は「30%」となります。

またその100人のうち、男性が50人いて、そのうち男性10人が「満足した」と答えた場合、
男性のサービス満足率は「20%」ですね。

さて、全体の「30%」と、そのうちの男性の「20%」は、
有意な差があるといえるでしょうか。

理論

全体のサービス満足率について改めて考えてみます。

100人のうち「30%」が満足したといっても、
改めてアンケート回答者を集めてくるところからもう一度やり直すと…

次は満足率「36%」という結果になるかもしれません。
もしかしたら「25%」になるかもしれません。

標本調査である以上仕方ありませんが、
「30%」という数値には本質的にばらつきが隠れています。

このばらつきをどう扱うか?

アンケートを何回もやり直した時のばらつき方ですが、
これは中心極限定理により正規分布というものに従ってばらつきます。

その前提と、今回のサンプルサイズ(100人)および割合(30%)から、
「標準誤差」というものを求めることができます。

標準誤差を求めることで、
「信頼度95%の場合、このサービスに満足した人は30±9%いたと思われる」
といった形で全体のサービス満足率を表現できます。

この「30±9%」の範囲が男性の「20%」とかぶっているかいないかで、
「全体の比率と一部(男性)の比率は有意に差があるか」を判定することが出来ます。
この例だと、「30±9%」と「20%」はかぶってないので、
「信頼度95%で有意に差がある」という結論になります。

この信頼区間を毎回求めて、かぶっているかどうかを毎回見るのもいいのですが、
先人はその判定を一撃で行うために、「統計量T」という、
一部の割合が全体の信頼区間内に入っているかどうかを計算するのと
同等の意味の式を編み出しました。

統計量T

$T=\dfrac {\left| p-p_{1} \right| }{\sqrt {p\left( 1-p\right) \dfrac {n-n_{1}}{n\times n_{1}}}}$1

$n$は全体のサンプルサイズ、$p$は全体の比率、
$n_1$は一部のサンプルサイズ、$p_1$は一部の比率とします。
※上の例なら、$n$は100人、$p$は0.3、$n_1$は50人、$p_1$は0.2。

この統計量Tは
「pとp1に本来差がない場合」は中心極限定理により正規分布するので、
この統計量Tが棄却限界値1.96以上であれば、
「この事象は正規分布の端っこの(異常な)出来事だ」ということになり、
結果として「95%の信頼度で有意に差がある」といえます。

ややこしいので一言でまとめると、

$T\geq 1.96$ ならば95%の信頼度で有意に差がある

です。

コード

ztest-type4.py
import sys
import math

def error_usage():
    sys.stderr.write("usage: " + sys.argv[0] + "\n")
    sys.stderr.write("\tこのプログラムは、4つの引数が必要です。\n\n")
    sys.stderr.write(
        "\t1.全体のn数 2.全体における比率 3.ある属性のn数 4.ある属性における比率\n")
    sys.stderr.write("\t例: 150 0.3 100 0.45\n\n")
    sys.stderr.write("\tただし、それぞれn数は30以上かつ比率pは[0<=p<=1]を満たすこと\n")
    sys.stderr.write("\t「1.全体のn数」は「3.ある属性のn数」より大きいこと\n")
    sys.exit(1)

# 引数がちょうど4つあるか?
if len(sys.argv[1:]) != 4:
    error_usage()

n,p,n1,p1 = map(float, sys.argv[1:])

# n数が30以上か?(n数が少なすぎないか?)
if (n < 30) or (n1 < 30):
    error_usage()

# nはn1より大きいか?
if n < n1 :
    error_usage()

# 比率は0から1の間か?
if not (0 <= p <= 1) or not (0 <= p1 <= 1):
    error_usage()

T = math.fabs(p - p1) / math.sqrt((p * (1-p)) * (n - n1)/(n * n1))

if T >= 2.58:
    print("1%有意 (検定統計量:" + str(T) + ")")
elif T >= 1.96:
    print("5%有意 (検定統計量:" + str(T) + ")")
elif T >= 1.65:
    print("10%有意 (検定統計量:" + str(T) + ")")
else:
    print("有意差なし")

このプログラムは、5%有意だけでなく、1%有意かどうか、10%有意かどうかも判定します。
ローカルに保存して実行してみましょう。
https://github.com/tochiji/ztest-type4/blob/ea4d5da26650ea0824a90c9ec3f964b297887b13/ztest-type4.py

結果

$ python3 ztest-type4.py 100 0.3 50 0.2
5%有意 (検定統計量:2.18218)

このコードをいつでも実行できるようにしたり、
シェルスクリプト化することで、あなたもすぐに検定ができるようになります。
よい検定ライフを。

補足

この検定は「母比率の差の検定/タイプ4」と言われたり、
「一部従属な比率の差の検定」と言われたりします。
あくまで「全体」とその「一部」の割合の差を比べるものなので、
例えば「男性」と「女性」といった、従属関係にないサービス満足度を比較するときは、
また別の統計検定量Tを使用する必要があります。
けものフレンズ1期の第一話は、2期の第一話より有意に面白いのか


  1. どうやってこれを導出するかはどこかで別途… 

1
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4