クロンバックの α

# クロンバックの α

クロンバックの α は質問紙の内的整合性を検討するために用いられる。

順序尺度変数やリッカート法により得られる回答データにも対応しているので，後述する "Kuder-Richardson の式 20" より優れている。

## 1.　定義

$$
α = \frac{k}{k-1} \left( \frac{\sum_{i≠j}^k \mathrm{cov}(x_i, x_j)}{\mathrm{var}(t)} \right) = \frac{k}{k-1} \left(1 -  \frac{\sum_{j=1}^k \mathrm{var}(x_j)}{\mathrm{var}(t)} \right)
$$

- $k$：質問項目数
- $x_j$：質問${}_j$への回答
- $t$：回答の合計 $t = \sum_{j=1}^k x_j$
- $\mathrm{cov}(x_i, x_j)$：質問${}_i$への回答と質問${}_j$への回答の不偏共分散
- $\mathrm{var}(x_i), var(t)$：質問${}_i$への回答，回答の合計の不偏分散

https://www.real-statistics.com/reliability/internal-consistency-reliability/cronbachs-alpha/cronbachs-alpha-basic-concepts/<br>
Cronbach’s Alpha Basic Concepts

## 2.　計算例

以下に示す 12 人に対して 11 の質問を行った結果の data を使用して計算を行う。

```julia
data = [1 1 1 1 1 1 1 1 1 1 1
        1 1 1 1 1 1 1 1 0 1 0
        1 0 1 1 1 1 1 1 1 0 0
        1 1 1 0 1 1 0 1 1 0 0
        1 1 1 1 1 0 0 0 1 0 0
        0 1 1 0 1 1 1 1 0 0 0
        1 1 1 1 0 0 1 0 0 0 0
        1 1 1 1 1 0 0 0 0 0 0
        0 1 0 1 1 0 0 0 0 1 0
        1 0 0 1 0 1 0 0 0 0 0
        1 1 1 0 0 0 0 0 0 0 0
        1 0 0 1 0 0 0 0 0 0 0];
```

```julia
k = size(data, 2)
```

    11

```julia
t = sum(data, dims=2)
```

    12×1 Matrix{Int64}:
     11
      9
      8
      7
      6
      6
      5
      5
      4
      3
      3
      2

```julia
using Statistics
varx = var(data, dims=1) # 不偏分散でも分散でも，以下と統一していればどちらでも可
```

    1×11 Matrix{Float64}:
     0.151515  0.204545  0.204545  0.204545  …  0.242424  0.204545  0.0833333

```julia
Σvarx = sum(varx)
```

    2.3409090909090913

```julia
vart = var(t) # 不偏分散でも分散でも，上と統一していればどちらでも可
```

    7.113636363636363

```julia
α = k / (k-1) * (1 - Σvarx / vart)
```

    0.7380191693290735

## 3.　Julia の関数として定義

上式の最初の式を関数化する。

```julia
using LinearAlgebra, Statistics
function alpha0(x)
    k = size(x, 2)
    VarCovMat = cov(x)
    Sy2 = sum(VarCovMat)
    Sj2 = sum(diag(VarCovMat))
    k / (k - 1) * (1 - Sj2 / Sy2)
end
```

    alpha0 (generic function with 1 method)

上式の 2 番目の式を関数化する。

```julia
using Statistics
function alpha(x)
    k = size(x, 2)
    varx = var(x, dims=1)
    y = sum(x, dims=2)
    k / (k - 1) * (1 - sum(varx) / var(y))
end
```

    alpha (generic function with 1 method)

## 4.　計算例

```julia
alpha0(data)
```

    0.7380191693290734

```julia
alpha(data)
```

    0.7380191693290735

以下のデータは 3 件法での回答を求めたものである。

```julia
data2 = [1 1 1
         2 1 1
         2 1 2
         3 2 1
         2 3 2
         2 3 3
         3 2 3
         3 3 3
         2 3 2
         3 3 3];
```

```julia
alpha0(data2)
```

    0.7734375

```julia
alpha(data2)
```

    0.7734375000000003

ちなみに，R では，psych::alpha で計算できる。

```julia
using RCall
R"""
library(psych)
results = alpha($(data2))
options(digits=16)
print(results$total$raw_alpha)
""";
```

    [1] 0.7734375

なお，`psych::alpha( )` は相関係数を与えるオプションもあるが，粗データを与えた場合と結果が違う。<br>

```julia
using RCall
R"""
library(psych)
results2 = alpha(cor($(data2)))
options(digits=16)
print(results2$total$raw_alpha)
""";
```

    [1] 0.7742910373931703

オンラインヘルプを見ると，

> When calculated from the item variances and total test variance, as is done here, raw alpha is sensitive to differences in the item variances. Standardized alpha is based upon the correlations rather than the covariances.

というくだりがある。つまり，変数（質問への回答）を標準化する方がよいとのことである。そこで，元データを標準化して `alpha( )` に与えてやると確かに同じ値になる。

```julia
using RCall
R"""
library(psych)
scaled = scale($(data2))
results2 = alpha(scaled)
options(digits=16)
print(results2$total$raw_alpha)
""";
```

    [1] 0.7742910373931704

## 5.　相関係数を与えて標準化されたクロンバックの α を求める

https://towardsdatascience.com/cronbachs-alpha-theory-and-application-in-python-d2915dd63586<br>
Cronbach’s Alpha: Theory and Application in Python

## 6.　定義

$$
\alpha_{st} = \frac{k \bar{r}}{1 +(k-1) \bar{r}}
$$

- $k$：質問項目数
- $\bar{r}$：質問項目間の相関係数の平均値（相関係数行列の対角要素を含まない上三角行列の相関係数 $r(i, j),  i < j$の平均値）

注意：元の Web ページのどこにも書いていないが，$\alpha_{st}$ と記述されている点に注意。つまり「標準化された ${}_{st}$ クロンバックのα）の意なのだ。

Web ページには Python での関数が示されている。

> def cronbach_alpha(df):    # 1. Transform the df into a correlation matrix
>     df_corr = df.corr()
>     
>     # 2.1 Calculate N
>     # The number of variables equals the number of columns in the df
>     N = df.shape[1]
>     
>     # 2.2 Calculate R
>     # For this, we'll loop through the columns and append every
>     # relevant correlation to an array calles "r_s". Then, we'll
>     # calculate the mean of "r_s"
>     rs = np.array([])
>     for i, col in enumerate(df_corr.columns):
>         sum_ = df_corr[col][i+1:].values
>         rs = np.append(sum_, rs)
>     mean_r = np.mean(rs)
>     
>     # 3. Use the formula to calculate Cronbach's Alpha 
>     cronbach_alpha = (N * mean_r) / (1 + (N - 1) * mean_r)
>     return cronbach_alpha

これを Julia に書き換える。

```julia
using Statistics

function cronbach_alpha(df)
    # 1. Transform the df into a correlation matrix
    r = cor(df)

    # 2.1 Calculate N
    # The number of variables equals the number of columns in the df
    N = size(df, 2)

    # 2.2 Calculate R
    # For this, we'll loop through the columns and append every
    # relevant correlation to an array calles "r_s". Then, we'll
    # calculate the mean of "r_s"
    r_s = []
    for i = 1:N-1
        for j = i+1:N
            append!(r_s, r[i, j])
        end
    end
    mean_r = mean(r_s)

    # 3. Use the formula to calculate Cronbach's Alpha 
    (N * mean_r) / (1 + (N - 1) * mean_r)
end
```

    cronbach_alpha (generic function with 1 method)

```julia
cronbach_alpha(data2)
```

    0.7742910373931704

確かに，`psych::alpha( )` の結果と一致した。

標準化というのは全ての変数の分散を同じにする（全ての変数を同格に扱う）ということである。<br>
普通にクロンバックの α が使われる状況は，質問項目の回答の分散が大きく変わることはない（ほとんどの質問項目は 5 件法，ある項目は 0 ~ 100 の満足度などというのはあり得ない）。<br>
なので，標準化されたクロンバックの α も，通常のクロンバックの α もほとんど同じ値になるだろう。<br>
クロンバックの α の応用法として，ある質問項目を除いたら α がどれぐらい変化するかを検討することがある。この場合に使うのは標準化されないクロンバックの α である。

ということで，伝統的な（標準化しない）クロンバックの α を使う方がよいだろう。

# Kuder and Richardson Formula 20

"Kuder-Richardson の式 20" は，クロンバックの α と同様に，質問紙の内的整合性を検討するためのものである。<br>
しかし，質問項目への回答が二値データ（たとえば 0/1）の場合に限られる。<br>
このような条件下では "Kuder-Richardson の式 20" は，クロンバックの α と全く同じ結果になる。

## 7.　定義

$$
\rho_{KR20} = \frac{k}{k-1}\left(1 - \frac{\sum_{j=1}^k p_jq_j}{\sigma^2}\right)
$$

- $k$：質問項目数
- $p_j$：質問${}_j$ に正解であった回答者数
- $q_j$：質問${}_j$ に不正解であった回答者数
- $\sigma^2$：回答者ごとの得点（正解数）の分散（不偏分散ではない）

$\rho_{KR20}$ は 0 ~ 1 の範囲の値をとり，値が大きいことは信頼性があることを示す。しかし，あまりにも大きい数値（たとえば 0.9 以上）の場合は，質問紙が均質である（悪い意味で「それぞれの質問はほとんど同じ」）ことを示す。

https://www.real-statistics.com/reliability/internal-consistency-reliability/kuder-richardson-formula-20/<br>
Kuder and Richardson Formula 20

## 8.　計算例

```julia
n, k = size(data)
```

    (12, 11)

```julia
p = sum(data, dims=1) ./ n
```

    1×11 Matrix{Float64}:
     0.833333  0.75  0.75  0.75  0.666667  …  0.416667  0.333333  0.25  0.0833333

```julia
q = 1 .- p
```

    1×11 Matrix{Float64}:
     0.166667  0.25  0.25  0.25  0.333333  …  0.583333  0.666667  0.75  0.916667

```julia
pq = p .* q
```

    1×11 Matrix{Float64}:
     0.138889  0.1875  0.1875  0.1875  0.222222  …  0.222222  0.1875  0.0763889

```julia
Σpq = sum(pq)
```

    2.1458333333333335

```julia
using Statistics
```

```julia
σ² = var(sum(data, dims=2), corrected=false) # 注：不偏分散ではない
```

    6.520833333333333

```julia
ρKR20 = (1 - Σpq / σ²) * k / (k - 1)
```

    0.7380191693290734

## 9.　Julia の関数として定義

```julia
using Statistics

function KR20(x)
    n, k = size(x)
    p = sum(data, dims=1) ./ n
    q = 1 .- p
    pq = p .* q
    Σpq = sum(pq)
    σ² = var(sum(data, dims=2), corrected=false)
    (1 - Σpq / σ²) * k / (k - 1)
end
```

    KR20 (generic function with 1 method)

前節の計算例のような 0/1 回答のデータに対して計算される "Kuder-Richardson の式 20" は，クロンバックの α と全く同じである。

```julia
alpha0(data)
```

    0.7380191693290734

```julia
alpha(data)
```

    0.7380191693290735

```julia
KR20(data)
```

    0.7380191693290734