はちみつブログ

趣味や生活の話を好きなタイミングで書いていきたいと思います。

クロンバックのα

久しぶりの統計・因子分析関連。今回はクロンバックのαについて紹介する。

はじめに-Cronbach(クロンバック)のαとは

因子分析ではひとつの因子から複数の観測できる変数が見えてくるという形になる。たとえば、性格検査を考えるとして、たくさんの似た質問に答えるイメージが持てるのではないかと思う。例えば「社交性」みたいなのを測りそうな似た質問がいくつかあって、それに答えると数値が上がるのかなぁ?みたいな。他だと、「理系因子」があって、その因子から数学や物理の点数に出てくるイメージだ。

先ほどの性格検査における似た質問という部分が、今回のクロンバックのαに関係する。ある因子があったとき、それに関わる質問、数値が複数ある場合、その複数の値がどれぐらい一貫性があるか、という値を表す。まあ、誤差というか、独立因子が大きすぎないよね、という意味なのかなと思ったりする。ちゃんとした性格検査の項目を作ったり、テスト項目を作ろうと思った際には、重要な内容になってくるはず。

クロンバックのαは、他でもよくあるが、0〜1の範囲の数値を取る。1に近いほど、一貫性のある値になっていることを示すようだ。(ただ、1は逆に同じ質問過ぎ) 相関でも一緒だと思うが、絶対的な数値の指標があるわけではないようだ(0.x以上だとオッケーみたいなのはないということ)。

ここからはまずは動かしてみて、どんな感じかな、と考えてみよう。

実際にどうやるか

テストデータを元にやり方を簡単に紹介。

テストデータ

たとえば、極端かもだが、以下のようなテストの点数があったとして、文系因子から国語、社会の点数が表れ、理系因子から数学と理科の点数が表れるとする。

ID 国語 社会 数学 理科
A 80 78 85 83
B 75 72 65 68
C 60 62 80 78
D 55 57 55 58
E 90 88 70 72

まあ、このままだと扱いにくいと思うので、標準化して扱うとは思うが、これのαを文系因子、理系因子ごとにPythonとRで求めてみようと思う。

Python

Pythonでやってみる。簡単な方法は pingouin を使うことのようだ。 pip でインストールする場合、以下のコマンドでインストールできる。

pip install pingouin

そして、こんなコードで求めることができる。

import pandas as pd
import pingouin as pg

df = pd.read_csv("07_cronbach-alpha/data/cronbach_alpha_test_data.csv")

bunkei = df[["Kokugo", "Shakai"]]
rikei = df[["Sugaku", "Rika"]]

bunkei_alpha, bunkei_ci = pg.cronbach_alpha(data=bunkei)
rikei_alpha, rikei_ci = pg.cronbach_alpha(data=rikei)

print("Bunkei alpha:", bunkei_alpha)
print("Bunkei CI:", bunkei_ci)

print("Rikei alpha:", rikei_alpha)
print("Rikei CI:", rikei_ci)

結果は以下のような感じ。

% python 07_cronbach-alpha/Python/cronbach_alpha.py 
Bunkei alpha: 0.991908482142857
Bunkei CI: [0.922 0.999]
Rikei alpha: 0.9855197752323319
Rikei CI: [0.861 0.998]

とりあえず文系に絞ると、αは0.991(以下略)、CIは信頼区間を表していて、95%信頼区間での数値が出てきている。

R

Rでやってみる。Rの場合、 psychパッケージを使うと求められる。 renv を使って、仮想環境に入れるとすると、該当のディレクトリで

R -q -e 'renv::init()'
R -q -e 'renv::install("psych")'
R -q -e 'renv::snapshot()'

これで概ね準備はできると思う。もし、自分のリポジトリからクローンして再現する場合は

R -q -e 'renv::restore()'

renv の状況を戻せるようなので、そのコマンドの方が良いかもしれない。

そして、本題のクロンバックのαは以下のようなコードで求められる。

library(psych)

df <- read.csv("../data/cronbach_alpha_test_data.csv")

bunkei <- df[, c("Kokugo", "Shakai")]
rikei <- df[, c("Sugaku", "Rika")]

bunkei_result <- alpha(bunkei)
rikei_result <- alpha(rikei)

print(bunkei_result)
print(rikei_result)

Rの方が、細かくいろいろ求められ、出力はこんな感じになるが

Reliability analysis   
Call: alpha(x = bunkei)

  raw_alpha std.alpha G6(smc) average_r S/N   ase mean sd median_r
      0.99         1    0.99      0.99 398 0.004   72 13     0.99

    95% confidence boundaries 
         lower alpha upper
Feldt     0.92  0.99     1
Duhachek  0.98  0.99     1

 Reliability if an item is dropped:
       raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
Kokugo      1.16      0.99    0.99      0.99 199       NA     0  0.99
Shakai      0.86      0.99    0.99      0.99 199       NA     0  0.99

 Item statistics 
       n raw.r std.r r.cor r.drop mean sd
Kokugo 5     1     1     1   0.99   72 14
Shakai 5     1     1     1   0.99   71 12

Reliability analysis   
Call: alpha(x = rikei)

  raw_alpha std.alpha G6(smc) average_r S/N    ase mean sd median_r
      0.99         1    0.99      0.99 366 0.0056   71 11     0.99

    95% confidence boundaries 
         lower alpha upper
Feldt     0.86  0.99     1
Duhachek  0.97  0.99     1

 Reliability if an item is dropped:
       raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
Sugaku       1.2      0.99    0.99      0.99 183       NA     0  0.99
Rika         0.8      0.99    0.99      0.99 183       NA     0  0.99

 Item statistics 
       n raw.r std.r r.cor r.drop mean   sd
Sugaku 5     1     1     1   0.99   71 11.9
Rika   5     1     1     1   0.99   72  9.6

ちょっと情報量が…笑 という感じだ。95%信頼区間も2手法で求めてくれていたりして、今後それぞれがどういう意味かは確認してみようかと思う。

情報量を落とす意味でも、αのみを抜き出すコードを足すと

bunkei_alpha <- bunkei_result$total$raw_alpha
rikei_alpha <- rikei_result$total$raw_alpha

cat("Bunkei alpha:", sprintf("%.16g", bunkei_alpha), "\n")
cat("Rikei alpha:", sprintf("%.16g", rikei_alpha), "\n")

こんな感じで、 raw_alpha を出力すればいいんだなとわかり、

Bunkei alpha: 0.991908482142857 
Rikei alpha: 0.9855197752323319 

桁数を指定しているからだが、Python版と同様の値を出力できる。

注意点

今回紹介した pingouinpsych もGPLのライセンスとなっている。単純にデータ分析として、αの計算にのみ用いるのであれば、商用利用でも何も問題ないと思う。一方で、もしこのαをはじめとした数値を使ったアプリケーションなどを作成して配布したい、などとなった場合は注意が必要になる。まあ、RはそもそもRがGPLなので、どちらかというとPythonで何かしたいケースとは思うし…まあ、クロンバックのαで何かすることを思いついていないが笑

感想になるが、MITライセンスとかの実装もあれば使いやすいのになぁと思ってしまうが…まあ、計測しかしないケースが多く、GPLでも誰も困っていないのだろうな。

クロンバックのαの出自について

1951年にCronbachさんが「Cronbach, Lee J. "Coefficient alpha and the internal structure of tests." psychometrika 16.3 (1951): 297-334. 」で提案したもののようだ。名前としても、Cronbachのαというのはそういうことなのだろう。簡単に中身も見てみたが、以下の式がはじめの方に出てきて、これがこれまで扱ってきたクロンバックのαになる。

$$ \alpha = \frac{n}{n-1} \left(1-\frac{\sum_{i=1}^{n} V}{V_t}\right) $$

$n$ は項目数。 $V_t$ の方が合計の方の分散。例えば国語と社会の合計の分散。 $V$の方が項目ごとの分散。例えば国語のみの分散や、社会のみの分散の合計だ。70年以上前の指標だが、今でもよく見る。なかなかに偉大な提案なんだろうな…

まとめ

今回はクロンバックのαを紹介した。久しぶりの統計系の回になったが、こんな感じでいろいろ調べているうちに気になったものを紹介するのもありかな、と思ってくるようになった。自分の勉強にもなるし。

今でもよく使われていて、自分も使っていきたいと思っているものの、一方で別な指標(McDonaldのωというのが調べて出てきた)も提案されてはいるようだ。おいおいこういうものも調べつつ、どれを使うのが良いか判断できるようなところを目指したい。

参考資料