まずは英語教育研究で用いられる分析の基礎となる回帰分析 (regression analysis) について紹介します。回帰分析とは、$y = ax + b +ε$のような関数で表される統計モデルです。yを目的変数 (outcome variable; 従属変数 [dependent variable] や応答変数 [response variable] とも)、xを説明変数 (explanatory variable; 独立変数 [independent variable] や予測変数 [predictor variable] とも)、aを傾き (slope)、bを切片 (intercept)、εは誤差 (error) と呼ばれます。例えば、期末テストの点数を中間テストの点数で予測する分析をする際、期末テスト = 中間テスト * x + b + 誤差と表されます。説明変数を含めた「中間テスト * x + b + 誤差」の結びつきは線形結合 (linear combination) と呼ばれています。このような線型結合の統計モデルに対し、xが2乗や3乗になったり、対数を取ったりする回帰モデルは非線形モデル (nonlinear model) と呼ばれます。
線型モデルは目的変数が正規分布 (normal distribution) に従うことを前提とします。そのため、線型モデルでは正規分布に従わないデータ (e.g., 正解・不正解のような2値データ、発生回数のような頻度) は扱うことができません。このような場合、「分析の前提を満たしていないため目的変数を対数変換した」「ボンフェローニ補正を用いたノンパラメトリック分析で検討した」のような分析が行われることがありますが、正規分布に従わないデータは一般化線型モデル (generalized linear model) を用いた分析を用いることが一般的です。一般化線型モデルを検討する前に、まずは基本となるt検定 (t-test) から復習していきましょう。
データセットは、50人の参加者が2種類の語彙学習方法を用いて比較された架空のデータです。この研究では、目標語彙に集中する学習方法がより効果的であると仮定します。具体的には、注釈付きの読解よりも、目標語彙を使用して文章を作る方が学習効果が高いと考えられます。参加者は15個ずつの目標語を2つの方法で学び、L2からL1への翻訳テスト (recall test) と選択問題 (recognition test) でその知識を評価します。このテストは学習直後と1週間後の遅延で実施しました。この実験設定を前提に、t検定をRで実施してみましょう。
t検定:各学習方法で15語ずつ学習し、15点満点のテストで評価します。再生テストと再認テストの両方でt検定を行います。
以下のコードを実行してデータセットを作成します。実際に作成されたデータセットはこちらです。
# パッケージの読み込み
library("tidyverse")
library("psych")
library("performance")
library("emmeans")
library("lmerTest")
library("DHARMa")
library("sjPlot")
library("effectsize")
# テーマと乱数種の設定
theme_set(theme_bw())
set.seed(123)
# サンプルデータの作成
# パラメータの設定
n_participants <- 50 # 50人の参加者
n_items <- 30 # 30項目の目標語
treatments <- c("Glossing", "Writing") # 学習条件は2種類
tests <- c("Recall", "Recognition") # テストは2種類
times <- c("Immediate", "Delayed") # テスト実施時期は2種類
# データフレームの作成
dat <- expand.grid(
Participant = 1:n_participants,
Item = 1:n_items,
Treatment = treatments,
Test = tests,
Time = times)
# アイテムの割り当てをTreatmentに基づいて修正
dat <- dat[dat$Treatment == "Glossing" & dat$Item <= 15 | dat$Treatment == "Writing" & dat$Item > 15, ]
# スコアの割り当て
dat$Score <- ifelse(
dat$Treatment == "Glossing",
rbinom(nrow(dat), 1, ifelse(dat$Test == "Recognition", 0.5, 0.2)), # Glossing: Recognition > Recall
rbinom(nrow(dat), 1, ifelse(dat$Test == "Recognition", 0.9, 0.5))) # Writing: Recognition > Recall
# Timeによるスコアの調整
dat$Score <- ifelse(
dat$Time == "Immediate",
dat$Score + sample(0:1, nrow(dat), replace = TRUE),
dat$Score)
# スコアが1を超えないように調整
dat$Score <- pmin(dat$Score, 1)
# csvとしてデータを出力
write.csv(dat, "sample.csv")
作成されたデータは50名の参加者に対して、2つの介入 (GlossingとWriting) を行っています。Glossingでは15語、Writingでは15語を学び、合計30語の目標語を学習します。その成果を直後と遅延で測定します。測定方法にはRecallとRecognitionの2種類のテストがあります。
このデータは以下のようにScoreの列が1か0の2値データとなっています。
> head(dat)
Participant Item Treatment Test Time Score
1 1 1 Glossing Recall Immediate 1
2 2 1 Glossing Recall Immediate 1
3 3 1 Glossing Recall Immediate 1
4 4 1 Glossing Recall Immediate 1
5 5 1 Glossing Recall Immediate 1
6 6 1 Glossing Recall Immediate 1
ロジスティック回帰分析は目的変数 (Score) が2値のまま実行できるのですが、t検定やMANOVAは実行できません。そこで以下のようにコードで連続値へと足して15点満点にする必要があります。
# 参加者ごとにスコアを集計
dat_summarized <- dat %>%
mutate(Participant = factor(Participant),
Item = factor(Item)) %>%
group_by(Participant, Treatment, Test, Time) %>%
summarize(Score = sum(Score), .groups = 'drop')
# 記述統計
(desc <- dat_summarized %>%
group_by(Treatment, Test, Time) %>%
summarise(
Mean = mean(Score),
SD = sd(Score),
N = n(),
SE = SD / sqrt(N),
CI_lower = Mean - 1.96 * SE,
CI_upper = Mean + 1.96 * SE
))
以下は参加者がTreatment、Test、Timeごとに15点満点のテストで何点かを表しています。
> head(dat_summarized)
# A tibble: 6 × 5
Participant Treatment Test Time Score
<fct> <fct> <fct> <fct> <dbl>
1 1 Glossing Recall Immediate 10
2 1 Glossing Recall Delayed 3
3 1 Glossing Recognition Immediate 11
4 1 Glossing Recognition Delayed 7
5 1 Writing Recall Immediate 14
6 1 Writing Recall Delayed 8
記述統計をプロットを見ると、RecallおよびRecognitionでImmediateの方がDelayedよりも高く、Writingの方がGlossingよりも高い点数である傾向があることがわかります。
t検定では目的変数が連続値、説明変数が1つで2水準のカテゴリカル変数である必要があります。そこで、そのようなデータセットを作成するため、以下のコードで直後と遅延ごとにRecallテストの結果をdat_imm、dat_delに格納します。
# 直後の再生テストのサブデータ
dat_imm <- dat_summarized %>%
dplyr::filter(Time == "Immediate",
Test == "Recall")
# 遅延の再生テストのサブデータ
dat_del <- dat_summarized %>%
dplyr::filter(Time == "Delayed",
Test == "Recall")