ランダム化割付の方法とR実装 ― 単純・置換ブロック・層別・最小化法をシミュレーションで比較する ―

記事の目次
Toggleこの記事でわかること
- 単純ランダム化・置換ブロック法・層別置換ブロック法・最小化法の違いと使い分けがわかります
- ブロックサイズをどう決めるか、なぜ固定サイズが危険なのかがわかります
- 4手法をRで実装するコードが手に入ります(blockrand・Minirandパッケージと自作関数の両方)
- 群サイズの不均衡・共変量の偏り・割付の予測可能性という3つのトレードオフを、シミュレーション結果で確認できます
- 層別因子の選び方、SAPへの記載、解析での層調整といった実務上の判断ポイントがわかります
はじめに
ランダム化(無作為化)は、臨床試験が「エビデンスの土台」と呼ばれるための中核をなす手続きです。その役割は大きく3つに整理できます。
1つめは、既知・未知の交絡因子を期待的に均等化することです。年齢や重症度のように測定できる因子だけでなく、生活習慣や遺伝的背景のように測定していない(あるいは測定できない)因子までを含めて、群間で確率的に釣り合わせられる点が観察研究との決定的な違いです。2つめは、選択バイアスの排除です。「この患者さんは重症だから実薬に入れたい」という担当医の善意が入り込むと、群間比較は容易に壊れます。誰がどちらの群に入るかを人の意思から切り離すことに、ランダム化の実務的な価値があります。3つめは、統計的推測の理論的正当性です。検定や信頼区間が意味を持つのは、割付という確率的な仕組みが背後にあるからこそです。
ICH E9「臨床試験の統計的原則」でも、ランダム化と盲検化はバイアスを避けるための最も重要なデザイン上の手法として位置づけられています。この考え方の全体像については、【完全理解】ICH E9「臨床試験の統計的原則」と補遺 もあわせてご覧ください。
ところが実務では、ランダム化の理解が「要するにコインを投げるということ」で止まってしまいがちです。実際の臨床試験でそのままコインを投げている試験は、ほとんどありません。置換ブロック法や層別置換ブロック法、あるいは最小化法といった、何らかの工夫を加えた方法が使われています。その理由は単純で、コイン投げでは群サイズが偏るからです。そして偏りを抑えようとすると、今度は「次の割付が読めてしまう」という別の問題が顔を出します。ランダム化の方法選択とは、この綱引きのどこに着地するかを決める作業にほかなりません。
本記事は前半で4つの割付法の理論を整理し、後半でRによる実装とシミュレーションによる比較を行います。試験デザイン全体の中でランダム化がどこに位置するのかを確認したい方は、臨床試験でよく使われる試験デザイン完全ガイド を先にご覧いただくと、以降の話がつながりやすくなります。プロトコルやSAPを書く立場の方、これから試験デザインを検討される方に、判断材料としてお使いいただければと思います。
代表的な4つのランダム化割付法
単純ランダム化(simple randomization)
各被験者を独立に確率1/2でA群・B群へ割り付ける、文字どおりコイン投げと同じ方法です。長所は明快で、割付が完全に予測不能であること、したがって選択バイアスが原理的に入り込めないこと、そして実装がきわめて簡単であることです。
一方の短所は、群サイズが偏ることです。ここで誤解されやすいのですが、症例数を増やせば偏りが解消されるわけではありません。確かに人数の「比」は1に近づいていきますが、人数の「差」の絶対値 \( |n_A-n_B| \) はむしろ大きくなり、そのオーダーは \( \sqrt{n} \) で増えていきます。100人の試験で二桁の差が生じることは、決して珍しい事態ではありません。1:1配分が最も検出力の高い配分である以上、この偏りは検出力の目減りに直結します。具体的にどの程度ずれるのかは、後半のシミュレーションで実測値をお示しします。こうした理由から、小〜中規模の試験で単純ランダム化がそのまま採用されることは、まずありません。
置換ブロック法(permuted block randomization)
一定人数の「ブロック」を単位として、その中にA群とB群が同数含まれる並びをランダムに選ぶ方法です。たとえばブロックサイズ4であれば、4人のうち2人がA群、2人がB群になる並びを選びます。その並びの総数は次のとおりです。
\[ \binom{4}{2}=6 \]
すなわち AABB、ABAB、ABBA、BAAB、BABA、BBAA の6通りから1つをランダムに選び、それをブロックごとに繰り返していきます。ブロックが埋まるたびに群サイズは必ず一致しますから、群サイズは常にほぼ均等に保たれます。症例登録が予定より早く打ち切られた場合でも均衡が崩れにくいのは、この方法の大きな利点です。
短所は予測可能性です。ブロックサイズが既知で、かつ非盲検の要素がある試験では、ブロック終盤の割付が読めてしまいます。ブロックサイズ4で最初の2人がAAだったなら、残りの2人は確実にBです。担当医がこれを知っていれば、「次はB群になる」と読んだうえで登録する患者を選ぶことができてしまい、選択バイアスが入り込みます。対策は2つあり、ブロックサイズを1種類に固定せず複数(たとえば4と6)を用意してランダムに混ぜること、そしてブロックサイズを試験関係者に開示しないことです。
層別置換ブロック法(stratified permuted block)
施設や疾患ステージのように、予後との関連が強い因子ごとに独立した割付表を用意し、それぞれの層の中で置換ブロック法を回す方法です。重要な予後因子について群間バランスを確保できるため、多施設共同試験では事実上の標準となっています。
短所は、層の数が爆発しやすいことです。因子が3つ(3水準×2水準×2水準)あるだけで層は12個になります。層が増えれば1層あたりの症例数は減り、ブロックが埋まらないまま試験が終わる層が出てきます。埋まらないブロックは群サイズが揃わないため、層ごとの端数が積み上がって全体の不均衡になります。層数はおおむね「症例数 ÷(ブロックサイズ×2)」を超えない程度、言い換えれば1層につきブロックが数個は埋まる見込みがあるか、という感覚で抑えるのが実務的です。
層別因子を増やせばバランスが良くなる、というのは誤解です。層を増やしすぎると各層でブロックが埋まらず、層ごとに生じた端数が積み上がって、かえって全体の不均衡が増えることがあります。層別は「多いほど良い」のではなく、予後との関連が強い因子を絞って使うものだとお考えください。
最小化法(minimization / Pocock-Simon法)
動的割付(dynamic allocation)の代表格です。新しい被験者が登録されたとき、「この人をA群に入れた場合」「B群に入れた場合」のそれぞれについて、既存の割付結果における共変量の偏りを表す指標を計算します。そして偏りが小さくなる方の群へ、高い確率 \( p \)(たとえば0.8)で割り付けます。
もっとも広く使われるRange法の不均衡指標は、次のように書けます。
\[ G_t=\sum_{f=1}^{F}\left(\max_k n_{f,\ell_f,k}^{(t)}-\min_k n_{f,\ell_f,k}^{(t)}\right) \]
ここで \( n_{f,\ell_f,k}^{(t)} \) は「その被験者を群 \( t \) に割り付けたと仮定したときの、因子 \( f \) の当該水準 \( \ell_f \) における群 \( k \) の人数」を意味します。つまり各因子について、その被験者が属する水準の中で群間人数の最大値と最小値の開きを求め、全因子について足し合わせたものが \( G_t \) です。この値が小さいほど、その割付を選んだときに全体のバランスが良いということになります。
なお \( p=1 \) とすると、常に偏りが小さくなる群へ確定的に割り付けることになり、割付が完全に決定論的になります。過去の割付結果から次が読めてしまうため、実務では \( p=0.7 \)〜\( p=0.9 \) 程度を用いるのが通例です。
長所は、層を作らずに多数の因子を同時にバランスできること、そのため症例数の少ない試験に強いことです。短所は、割付が過去の割付結果に依存するため厳密な意味でのランダム割付ではないこと、実装に中央割付システム(IWRS/IRT)が必要になることです。規制当局が動的割付に慎重な見方を示してきた経緯もありますが、その規制上の位置づけについては後述します。
| 割付法 | 群サイズの均衡 | 共変量バランス | 予測可能性(選択バイアス) | 主な用途 |
|---|---|---|---|---|
| 単純ランダム化 | △ 症例数が増えても差の絶対値は縮まらない | △ 期待的には均等だが個々の試験では偏る | ◎ 完全に予測不能 | 大規模試験、方法論の基準としての位置づけ |
| 置換ブロック法 | ◎ ブロックが埋まるたびに一致 | △ 全体の均衡のみで因子別の保証はない | △ ブロック終盤が読める(サイズ混在で緩和) | 単施設試験、盲検性が保たれる試験の基本形 |
| 層別置換ブロック法 | ○ 層内は均衡、端数の積み上がりに注意 | ○ 層別した因子は確保、それ以外は未保証 | △ 置換ブロック法と同じ課題を持つ | 多施設共同試験の標準、予後因子が少数の場合 |
| 最小化法 | ○ 全体としてほぼ均等に保たれる | ◎ 多因子を同時にバランスできる | △ 過去の割付に依存(確率 \( p \) で緩和) | 小規模試験、バランスすべき因子が多い試験 |
いずれの手法にも一長一短があり、「常にこれが正解」という割付法は存在しません。試験の規模、盲検性、登録スピード、そしてバランスさせたい因子の数によって最適解が変わります。次のセクションからは、この4手法を実際にRで実装し、トレードオフの大きさを数値で確認していきます。

Rでランダム化を実装する
ここからは、これまで説明してきた4つの割付法を実際にRのコードで動かしていきます。以下のコードはすべてR 4.5.1で実行しており、乱数シードを set.seed(4869) で固定していますので、同じコードをそのまま実行すれば同じ結果が再現できます。パッケージは blockrand と Minirand を使いますが、置換ブロック法と最小化法については自作関数での実装も並べて示します。アルゴリズムの中身が見えていると、SAP(統計解析計画書)に割付方法を記載するときや、割付ベンダーのIWRS仕様書をレビューするときに、何を確認すべきかを自分の言葉で判断できるようになるからです。
単純ランダム化 ― 群サイズはどれくらい偏るのか
まずは最も素朴な単純ランダム化です。各被験者を独立に確率1/2でA群・B群へ振り分けるだけですので、Rでは sample() の一行で書けます。
set.seed(4869)
# 単純ランダム化:各被験者を独立に確率1/2でA群・B群へ
simple_rand <- function(n) sample(c("A", "B"), size = n, replace = TRUE)
# 20人に割り付けてみる
alloc <- simple_rand(20)
table(alloc)
> alloc
> A B
> 11 9
20人を割り付けた結果は11対9でした。コイン投げを20回して表が11回出るのと同じことですので、これ自体は何も不思議ではありません。問題は、この「ちょっとした偏り」が試験の規模を大きくしても消えてくれないことです。群サイズの差 \( |n_A-n_B| \) を10,000回シミュレーションして、症例数ごとにどのような分布になるかを確認します。
# 群サイズの差 |nA - nB| を10,000回シミュレーション
sim_imbalance <- function(n, nsim = 10000) {
d <- replicate(nsim, {
tab <- table(factor(simple_rand(n), levels = c("A", "B")))
abs(tab[1] - tab[2])
})
data.frame(n = n,
mean_diff = round(mean(d), 2),
p_diff_ge4 = round(mean(d >= 4), 3),
p_diff_ge10 = round(mean(d >= 10), 3),
max_diff = max(d))
}
do.call(rbind, lapply(c(50, 100, 200), sim_imbalance))
> n mean_diff p_diff_ge4 p_diff_ge10 max_diff
> 1 50 5.65 0.675 0.208 26
> 2 100 7.95 0.765 0.367 40
> 3 200 11.18 0.841 0.520 56
n=100の試験でも、群サイズの差の平均は7.95人あります。4人以上ずれる確率は76.5%、10人以上ずれる確率でさえ36.7%です。さらに注目すべきは、症例数を50→100→200と増やしたときに、差の平均が5.65→7.95→11.18と大きくなっていることです。「nを増やせば偏りは消える」というのは比率(\( n_A/n \) が0.5に近づくこと)の話であって、差の絶対値は \( \sqrt{n} \) のオーダーで増えていきます。最悪ケースはn=200で56人差でした。1:1配分が最も検出力の高い割り当てですので、50:50を前提に症例数設計をした試験でこの不均衡が起きれば、そのぶん検出力を失うことになります。
置換ブロック法を自作関数で書く
次は置換ブロック法です。ブロックサイズを4または6からランダムに選び、各ブロックの中にA・Bを同数含む並びを作ります。ブロックが一つ埋まるたびに群サイズが必ず揃うのがポイントです。
set.seed(4869)
# 置換ブロック法:ブロックサイズを4または6からランダムに選び、
# 各ブロック内でA・Bを同数含む並びをランダムに作る
perm_block <- function(n, block_sizes = c(4, 6), arms = c("A", "B")) {
out <- character(0)
while (length(out) < n) {
b <- sample(block_sizes, 1)
out <- c(out, sample(rep(arms, each = b / 2)))
}
out[1:n]
}
pb <- perm_block(20)
matrix(pb, nrow = 2, byrow = TRUE, dimnames = list(c("1-10", "11-20"), 1:10))
table(pb)
> 1 2 3 4 5 6 7 8 9 10
> 1-10 "A" "A" "B" "B" "B" "B" "A" "A" "B" "B"
> 11-20 "B" "A" "A" "A" "A" "A" "B" "B" "B" "A"
> pb
> A B
> 10 10
20人ちょうどで10対10と、きれいに揃いました。ただし本当に見るべきは最終的な人数ではなく、「途中経過でどれだけ偏っているか」です。A群を+1、B群を-1として累積和を取ると、登録の各時点での不均衡が可視化できます。
# 累積の不均衡(A群を+1、B群を-1として累積和をとる)
cumsum(ifelse(pb == "A", 1, -1))
> [1] 1 2 1 0 -1 -2 -1 0 -1 -2 -3 -2 -1 0 1 2 1 0 -1 0
累積不均衡は最大でも3人(11人目の時点の -3)にとどまり、常にゼロ付近を上下していることがわかります。単純ランダム化のように一方向へずるずると流れていく動きがありません。これは実務上とても重要な性質です。中間解析の時点でも、症例登録が予定より早く打ち切られたときでも、群サイズがほぼ揃った状態が保たれているということだからです。
blockrandパッケージで割付表を作る
実務では割付表を自作するより、検証されたパッケージを使うほうが安全です。blockrand パッケージは置換ブロック法の標準的な実装で、ブロックIDやブロックサイズの列まで付けてくれます。
library(blockrand)
set.seed(4869)
# block.sizes は「ブロックサイズ ÷ 群数」で指定する(2 と 3 → ブロックサイズ4と6)
bl <- blockrand(n = 12, num.levels = 2, levels = c("A", "B"),
block.sizes = c(2, 3))
bl
> id block.id block.size treatment
> 1 1 1 4 A
> 2 2 1 4 B
> 3 3 1 4 B
> 4 4 1 4 A
> 5 5 2 4 B
> 6 6 2 4 A
> 7 7 2 4 A
> 8 8 2 4 B
> 9 9 3 6 B
> 10 10 3 6 A
> 11 11 3 6 B
> 12 12 3 6 A
> 13 13 3 6 A
> 14 14 3 6 B
この出力には、実務で必ず引っかかる点が2つ含まれています。1つ目は
block.sizes の意味です。これは「ブロックサイズそのもの」ではなく「ブロックサイズ÷群数」を指定します。c(2, 3) と書いたことで、実際に生成されたのは block.size 列にあるとおりサイズ4と6のブロックです。ここを取り違えると、意図の倍のサイズのブロックで割付表を作ってしまいます。2つ目は行数です。n=12を指定したのに14行返っています。blockrandは最後のブロックを途中で切らずブロック単位で完結させるため、指定人数を超えた割付表になることがあります。この余剰行は消さずに残しておくと、症例登録が予定を上回ったときにそのまま使えます。また block.id と block.size の列があることで、どのブロックまで埋まっているかという割付表の品質管理にも使えます。層別置換ブロック法 ― 施設ごとに独立した割付表を持つ
層別置換ブロック法は、施設や疾患ステージといった予後因子の水準ごとに、独立した置換ブロックの割付表を用意する方法です。blockrand では stratum 引数で層のラベルを付けられますので、層ごとに関数を呼んで縦に結合します。
set.seed(4869)
# 施設ごとに独立した割付表を作る(3施設 × 各8人)
strata <- c("Site1", "Site2", "Site3")
bl_st <- do.call(rbind, lapply(strata, function(s) {
blockrand(n = 8, num.levels = 2, levels = c("A", "B"),
block.sizes = c(2, 2), stratum = s,
id.prefix = paste0(s, "-"), block.prefix = paste0(s, "-"))
}))
head(bl_st, 10)
table(bl_st$stratum, bl_st$treatment)
> id stratum block.id block.size treatment
> 1 Site1-1 Site1 Site1-1 4 A
> 2 Site1-2 Site1 Site1-1 4 B
> 3 Site1-3 Site1 Site1-1 4 B
> 4 Site1-4 Site1 Site1-1 4 A
> 5 Site1-5 Site1 Site1-2 4 B
> 6 Site1-6 Site1 Site1-2 4 A
> 7 Site1-7 Site1 Site1-2 4 A
> 8 Site1-8 Site1 Site1-2 4 B
> 9 Site2-1 Site2 Site2-1 4 B
> 10 Site2-2 Site2 Site2-1 4 B
>
> A B
> Site1 4 4
> Site2 4 4
> Site3 4 4
3施設すべてで4対4となり、施設という予後因子について完全にバランスが取れました。被験者IDにも Site1-1 のように層のラベルが入りますので、施設へ割付表を配布するときの取り違えも防げます。
この「各層で4対4」という結果は、各施設でちょうど8人(ブロックサイズ4が2つ分)を登録できたという理想的な条件のもとで得られたものです。実際の多施設試験では施設ごとの登録数が大きくばらつき、5人しか登録できない施設や、ブロックの途中で登録が終わる施設が必ず出ます。その場合、その層では埋まりきらなかったブロックのぶんだけ不均衡が残り、それが層の数だけ積み上がります。層を細かく切りすぎると全体の不均衡がかえって増えるのは、この端数が層の数だけ発生するためです。
最小化法(Pocock-Simon法)を自作実装する
最小化法は、新しい被験者が登録されるたびに「A群に入れた場合」「B群に入れた場合」それぞれの共変量の不均衡スコアを計算し、スコアが小さくなるほうへ高い確率で割り付ける動的割付です。ここではRange法のスコアを使い、割付確率 \( p=0.8 \) で実装します。
set.seed(4869)
# 最小化法:新しい被験者をA/Bどちらに入れると
# 共変量の不均衡(Range法のスコア)が小さくなるかを計算し、
# 小さくなる方へ確率 p = 0.8 で割り付ける
minimize_alloc <- function(factors, assigned, new_pt, p = 0.8, arms = c("A", "B")) {
score <- sapply(arms, function(a) {
total <- 0
for (f in names(new_pt)) {
cnt <- sapply(arms, function(b)
sum(factors[[f]][assigned == b] == new_pt[[f]], na.rm = TRUE))
cnt[a] <- cnt[a] + 1
total <- total + diff(range(cnt))
}
total
})
best <- arms[which.min(score)]
other <- setdiff(arms, best)
if (length(unique(score)) == 1) sample(arms, 1)
else sample(c(best, other), 1, prob = c(p, 1 - p))
}
# 100人・3つの層別因子(施設・年齢・ECOG PS)を持つ仮想集団
n <- 100
pts <- data.frame(
site = sample(c("S1", "S2", "S3"), n, TRUE, prob = c(.5, .3, .2)),
age = sample(c("<65", ">=65"), n, TRUE, prob = c(.6, .4)),
ecog = sample(c("0", "1"), n, TRUE, prob = c(.7, .3)),
stringsAsFactors = FALSE)
assigned <- character(n)
for (i in seq_len(n)) {
if (i <= 2) {
assigned[i] <- sample(c("A", "B"), 1)
} else {
assigned[i] <- minimize_alloc(
factors = lapply(pts[1:(i - 1), ], identity),
assigned = assigned[1:(i - 1)],
new_pt = as.list(pts[i, ]), p = 0.8)
}
}
table(assigned)
table(pts$site, assigned)
table(pts$age, assigned)
table(pts$ecog, assigned)
> assigned
> A B
> 51 49
> assigned
> A B
> S1 25 26
> S2 15 12
> S3 11 11
> assigned
> A B
> <65 31 31
> >=65 20 18
> assigned
> A B
> 0 36 35
> 1 15 14
全体は51対49、そして3つの因子のすべての水準で群間差が最大3人(S2の15対12)に収まっています。ここで比較していただきたいのが、同じことを層別置換ブロック法でやろうとした場合です。施設3水準×年齢2水準×ECOG 2水準で12層が必要になり、100人をその層数に分けたのではブロックがまともに埋まりません。最小化法は層を一つも作らずに3因子を同時にバランスさせています。これが小規模試験や多因子の試験で最小化法が選ばれる最大の理由です。ただし注意点があります。この方法は各因子を個別に(周辺分布として)バランスさせているだけですので、「S1かつ65歳以上かつECOG 1」といった因子の組み合わせ(交互作用セル)までバランスすることは保証されません。
Minirandパッケージで同じことをする
最小化法にも実装済みのパッケージがあります。Minirand パッケージは因子ごとの重み covwt や割付比 ratio を指定できる標準的な実装です。先ほどと同じ仮想集団 pts に対して適用してみます。
library(Minirand)
set.seed(4869)
covmat <- pts[, c("site", "age", "ecog")] # 層別因子
covwt <- c(1/3, 1/3, 1/3) # 各因子の重み
ratio <- c(1, 1) # 1:1配分
res_mr <- numeric(100)
res_mr[1] <- sample(1:2, 1, replace = TRUE, prob = ratio / sum(ratio))
for (j in 2:100) {
res_mr[j] <- Minirand(covmat = covmat, j, covwt = covwt, ratio = ratio,
ntrt = 2, trtseq = c(1, 2), method = "Range",
result = res_mr, p = 0.8)
}
table(res_mr)
> res_mr
> 1 2
> 51 49
自作関数とまったく同じ51対49になりました。引数の意味も先ほどのコードと対応しています。method = "Range" は上で定義した不均衡指標そのもの、covwt は因子ごとの重みで、特に重視したい因子に大きい値を与えます。p = 0.8 は「不均衡が小さくなる群へ割り付ける確率」です。実務では自作せずにこうしたパッケージ(あるいは割付ベンダーのIWRS)を使えば十分ですが、中身が数十行のコードで書ける程度の単純なアルゴリズムだと知っておくと、SAPに手法を記述するときや、ベンダーから提示された割付仕様書のパラメータ設定を確認するときに、迷わず読み解けるようになります。
シミュレーションで比較する ― 不均衡・予測可能性・共変量バランス
ここまでで4手法をすべて実装できましたので、次はそれらを同じ土俵で比較します。比較の軸は、①群サイズの不均衡、②割付の予測可能性、③共変量バランスの3つです。この3つはトレードオフの関係にあり、どれか一つを完璧にすると別のどれかが犠牲になります。実測値で確認していきましょう。
群サイズの不均衡を比べる
100人の試験を500回繰り返し、単純ランダム化と置換ブロック法で群サイズの差がどうなるかを比較します。
set.seed(4869)
nsim <- 500; n <- 100
imb_simple <- replicate(nsim, {
a <- simple_rand(n); abs(sum(a == "A") - sum(a == "B"))
})
imb_block <- replicate(nsim, {
a <- perm_block(n, c(4, 6)); abs(sum(a == "A") - sum(a == "B"))
})
round(c(simple_mean = mean(imb_simple), simple_max = max(imb_simple),
block_mean = mean(imb_block), block_max = max(imb_block)), 2)
> simple_mean simple_max block_mean block_max
> 8.5 28.0 0.4 2.0
差は歴然としています。単純ランダム化は平均8.5人差で、最悪のケースでは28人差、つまり64対36という配分になりました。一方、置換ブロック法は平均0.4人差、最悪でも2人差です。500回繰り返しても、最も偏った回でさえ2人しかずれなかったということになります。100人規模の試験で64対36が現実的に起こりうるレンジだという事実こそが、置換ブロック法が実務の標準になっている最大の理由です。しかもこの均衡は最終時点だけでなく登録の途中でも保たれますので、中間解析やDSMBへの報告の際にも群サイズを気にする必要がありません。
割付の予測可能性を比べる
置換ブロック法の代償が予測可能性です。ここでは「次の割付を当てにいく」戦略、具体的にはBlackwell-Hodgesの考え方に沿って「これまで人数が少ないほうの群」を予想し続けたときに、何%当てられるかをシミュレーションします。ブロックサイズを固定した場合と、複数を混ぜた場合を比べます。
set.seed(4869)
# 「これまで少ない方の群」を予想し続けたときの的中率
guess_rate_block <- function(block_sizes, n = 200, nsim = 2000) {
hits <- replicate(nsim, {
seqs <- perm_block(n, block_sizes)
cum <- 0; correct <- 0
for (i in seq_len(n)) {
g <- if (cum > 0) "B" else if (cum < 0) "A" else sample(c("A", "B"), 1)
correct <- correct + (g == seqs[i])
cum <- cum + ifelse(seqs[i] == "A", 1, -1)
}
correct / n
})
mean(hits)
}
round(c(block4 = guess_rate_block(4),
block6 = guess_rate_block(6),
block46 = guess_rate_block(c(4, 6))), 3)
> block4 block6 block46
> 0.729 0.709 0.693
この数値はランダム化の設計で最も重く受け止めるべき結果です。単純ランダム化なら的中率は理論上ちょうど0.5、つまり当てずっぽうと同じで予測不能です。ところがブロックサイズ4を固定すると、何の秘密情報も使わず「少ないほうの群を答え続ける」だけで72.9%が当たってしまいます。非盲検試験で担当医がブロックサイズを知っていれば、「次はB群になりそうだ」と読んだうえで登録する患者を選ぶことができ、選択バイアスが入り込みます。ブロックサイズを6にすると70.9%、4と6をランダムに混ぜると69.3%まで下がります。ブロックサイズを複数用意して混ぜること、そして関係者にブロックサイズを開示しないことが実務の標準になっている根拠が、この数値です。ただし混ぜても69.3%であり、0.5には遠く及びません。置換ブロック法は「群サイズの均衡と引き換えに、ある程度の予測可能性を受け入れている」手法である、という理解が必要です。
共変量バランスを比べる
3つ目の軸は共変量バランスです。施設3水準・年齢2水準・ECOG PS 2水準という3因子を持つ100人の集団を300回生成し、各因子の各水準における群間人数差の最大値を、単純ランダム化・施設のみで層別した置換ブロック法・3因子を使った最小化法の3手法で比較します。
set.seed(4869)
nsim <- 300; n <- 100
max_factor_imb <- function(assign, pts) {
m <- 0
for (f in names(pts)) {
tb <- table(pts[[f]], factor(assign, levels = c("A", "B")))
m <- max(m, max(abs(tb[, 1] - tb[, 2])))
}
m
}
sim_one <- function() {
pts <- data.frame(
site = sample(c("S1", "S2", "S3"), n, TRUE, prob = c(.5, .3, .2)),
age = sample(c("<65", ">=65"), n, TRUE, prob = c(.6, .4)),
ecog = sample(c("0", "1"), n, TRUE, prob = c(.7, .3)),
stringsAsFactors = FALSE)
a_simple <- simple_rand(n)
a_strat <- character(n) # 施設のみで層別
for (s in unique(pts$site)) {
idx <- which(pts$site == s)
a_strat[idx] <- perm_block(length(idx), c(4, 6))
}
a_min <- character(n) # 3因子で最小化
for (i in seq_len(n)) {
if (i <= 2) a_min[i] <- sample(c("A", "B"), 1)
else a_min[i] <- minimize_alloc(lapply(pts[1:(i-1), ], identity),
a_min[1:(i-1)], as.list(pts[i, ]), p = 0.8)
}
c(simple = max_factor_imb(a_simple, pts),
strat = max_factor_imb(a_strat, pts),
minim = max_factor_imb(a_min, pts))
}
out <- t(replicate(nsim, sim_one()))
data.frame(method = c("simple", "stratified block", "minimization"),
mean_max_imbalance = round(colMeans(out), 2),
p90 = apply(out, 2, quantile, 0.9),
worst = apply(out, 2, max),
row.names = NULL)
> method mean_max_imbalance p90 worst
> 1 simple 10.23 16 27
> 2 stratified block 5.89 10 16
> 3 minimization 2.81 5 10
単純ランダム化では、いずれかの因子水準で平均10.23人、最悪では27人もの群間差が生じています。100人の試験で、ある因子の水準の患者が一方の群に27人多いという状況は、ベースライン表を見た読み手が結果を信用しなくなるレベルの偏りです。施設だけで層別した置換ブロック法は平均5.89人まで改善しますが、層別していない年齢・ECOGの偏りはそのまま残ります。90パーセンタイルで10人差、最悪16人差というのがその表れです。層別は「層別した因子にしか効かない」という当たり前の事実が数値で見えています。3因子を使った最小化法は平均2.81人、90パーセンタイルでも5人、最悪でも10人差と最も安定しています。ただしこの優位性は「バランスさせたい因子をすべて割付アルゴリズムに入れられた場合」の話です。因子の選定を誤れば意味がありませんし、割付が過去の割付結果に依存するぶん予測可能性は残ります。
ここまでの3軸の実測値を1つの表にまとめます。実際に測定した値のみを載せ、測定していない欄は「―」としています。
| 手法 | 群サイズ差 平均 | 共変量の最大不均衡 平均 | 割付の的中率 | コメント |
|---|---|---|---|---|
| 単純ランダム化 | 8.5人(最悪28人) | 10.23人(最悪27人) | 0.500(理論値) | 予測は完全に不可能だが、群サイズも共変量も最も偏る |
| 層別置換ブロック法 | 0.4人(最悪2人) | 5.89人(最悪16人) | 0.693(サイズ4と6を混合) | 群サイズはほぼ完璧。層別した因子以外の偏りは残り、予測可能性が代償になる(群サイズ差と的中率は層別なしの置換ブロック法での実測値) |
| 最小化法 | ―(実測は51対49) | 2.81人(最悪10人) | ― | 層を作らず多因子を同時にバランス。割付が過去に依存する点は理解が必要 |
群サイズの差は8.5人から0.4人へ、共変量の最大不均衡は10.23人から2.81人へと、手法を変えるだけで大きく改善します。しかしその代わりに、的中率は0.500から0.693へ上がってしまいます。ランダム化の手法選択とは、この3つの数値のどれをどこまで許容するかという判断そのものです。試験の規模、盲検性が保たれているか、どの因子が予後を強く規定するか、症例登録のスピードはどうか。これらの条件によって最適解は変わります。

実務でのポイント
ここまでで4つの割付法の性質を、実際にRを動かした数値で確認してきました。ここからは、プロトコルやSAP(統計解析計画書)を書く立場に立ったときに、実際に判断を迫られるポイントを整理していきます。手法の理論を知っていることと、自分の試験に合わせて選び、文書に落とし込めることは別のスキルだからです。
層別因子は「予後との関連が強く」「数を絞って」選ぶ
層別ランダム化を計画するとき、最初に決めるのが「何で層別するか」です。ここで押さえておきたい原則は2つあります。1つは、層別因子は主要評価項目との関連が強い予後因子に限る、ということ。関連の弱い因子で層別しても、群間比較の精度はほとんど向上しません。もう1つは、因子の数を絞る、ということです。
多施設共同試験でもっとも一般的な層別因子は施設です。施設が違えば診療の実態も、集まってくる患者さんの背景も違うため、施設は事実上の強力な予後因子として働きます。加えて、がん領域であれば病期やECOG PS、循環器領域であれば重症度分類といった、その疾患領域で標準的に使われている予後因子を1つか2つ追加する、というのが典型的な設計です。
因子を増やしたくなる気持ちはよくわかりますが、層別置換ブロック法では因子を1つ増やすたびに層の数が掛け算で増えていきます。層が増えれば1層あたりの症例数が減り、ブロックが埋まらないまま試験が終了する層が出てきます。ブロックが埋まらない層では、その層内の割付は実質的に単純ランダム化と変わりません。「バランスを良くするために層別したのに、かえって不均衡が増えた」という本末転倒が起こるのは、この理屈によるものです。目安としては、1つの層に少なくともブロック数個分の症例が見込めること、つまり層数は想定症例数に対して十分に小さく保つこと、と考えておくとよいでしょう。
ブロックサイズは複数用意し、関係者に開示しない
シミュレーションで確認したとおり、ブロックサイズを4に固定すると、「これまで少ない方の群を予想する」という単純な戦略だけで次の割付を72.9%当てられてしまいます。これは統計的な小言ではなく、選択バイアスという実害に直結します。次の患者がB群に入ると読める状況では、担当医が(意識的であれ無意識であれ)「この患者はB群向きだから今登録しよう」「A群になるまで登録を待とう」という判断をしうるからです。
実務上の対策は2つです。第一に、ブロックサイズを複数用意してランダムに混ぜること。第二に、ブロックサイズを試験関係者に開示しないことです。プロトコル本文には「置換ブロック法を用いる」とだけ記載し、具体的なブロックサイズは統計担当者のみがアクセスできる割付仕様書(randomization specification)に書く、という運用が広く採られています。
二重盲検試験では、割付結果そのものが見えないため予測可能性のリスクは相対的に下がります。しかしオープンラベル試験やPROBE試験(評価者のみ盲検化する試験)では、割付結果が登録直後に判明するため、ブロックサイズの漏洩は致命的です。「盲検化していないからこそ、ランダム化の設計をより慎重にする」という発想が必要になります。
ランダム化で考慮した層別因子は、解析でも調整する
意外と見落とされやすいのがこの点です。ICH E9「臨床試験の統計的原則」でも、デザインの段階で考慮した層別因子は主要解析でも共変量として調整するのが原則という考え方が示されています。層別してランダム化したにもかかわらず解析でその因子を無視すると、検定の性能に影響しうるためです。直感的には「バランスが取れているのだから調整してもしなくても同じでは」と思いがちですが、層別によって割付の変動が小さくなっているぶん、調整しない解析は保守的になり検出力を損なう方向に働きます。詳しくは共変量調整(ANCOVA)徹底解説 ― FDA・EMAガイダンスとR・SASでおよび【完全理解】ICH E9「臨床試験の統計的原則」と補遺をご覧ください。
最小化法を用いた場合も考え方は同じで、バランスに使った因子を共変量として調整したモデルを主要解析に据えるのが一般的です。加えて、割付が過去の割付結果に依存するという最小化法の性質を踏まえ、再ランダム化検定(randomization test)を感度分析として実施する、という考え方もあります。
最小化法の規制上の位置づけ
最小化法については、規制当局が長く慎重な姿勢を示してきた経緯があります。EMA/CHMPの “Guideline on adjustment for baseline covariates in clinical trials”(EMA/CHMP/295050/2013)では、動的割付(dynamic allocation)について「強く推奨されない(strongly discouraged)」という立場が明示されています。そのうえで、もし用いる場合には割付に使用したすべての因子を解析の共変量に含めることが必須である、という整理がなされています。禁止されているわけではありませんが、層別置換ブロック法で目的が達成できるのであればそちらを選ぶほうが、規制上の説明ははるかに容易だとお考えください。
背景にあるのは、割付が完全にランダムではないため、通常の検定が前提とする理論的な根拠がやや弱くなるという批判です。一方で、症例数が限られる試験で多数の予後因子を同時にバランスできるという利点は実務上とても大きく、実際に希少疾患領域やがん領域では広く使われています。重要なのは、最小化法を採用するなら「なぜ層別ブロック法では不十分なのか」をプロトコルで説明し、バランスに用いる因子・その重み・割付確率まで具体的に明記しておくことです。
実装は中央割付(IWRS/IRT)が前提になる
かつて広く使われた封筒法(あらかじめ割付を封入した封筒を施設に配布する方式)は、封筒を透かして中身を見る、順番を入れ替える、開封済みの封筒を戻すといった形で割付の隠蔽(allocation concealment)が破られやすく、現在では推奨されません。実務上は、Web/音声で中央のシステムに登録するIWRS(Interactive Web Response System)やIRT(Interactive Response Technology)を用いるのが標準です。特に最小化法は、それまでの全被験者の割付結果を参照して次を決めるアルゴリズムであるため、中央割付なしでは原理的に実施できません。
もう1つ実務的に重要なのが再現性の確保です。本記事のコードで set.seed() を使ったのと同じ発想で、割付表を生成した際の乱数シードとスクリプトは必ず記録し、後から同じ割付表を再現できる状態にしておきます。監査や当局照会で「この割付表はどう作られたのか」を問われた際に、手順書とシードだけで再現できることは大きな安心材料になります。もちろん、生成された割付表そのものは、盲検解除まで統計担当者以外がアクセスできないよう厳格に管理する必要があります。
1:1以外の配分比を使うとき
配分比は1:1が基本ですが、2:1(実薬群を多く割り付ける)配分も珍しくありません。実薬群の安全性情報をより多く集めたい場合や、「プラセボに入る確率が低い」ことで被験者の受け入れが良くなり登録が進みやすくなる、といった実務的な理由があるためです。
ただし、同じ総症例数であれば1:1配分が最も検出力が高いという事実は必ず押さえておいてください。2:1にするなら、その分だけ総症例数を増やす必要があります。また、置換ブロック法で2:1を実現する場合、ブロックサイズは3の倍数にする必要があります(例:ブロックサイズ6なら実薬4例・対照2例)。ブロックサイズを混在させる場合も、6と9のように3の倍数の中から選ぶことになります。
| 試験の状況 | 第一候補となる割付法 | 判断のポイント |
|---|---|---|
| 大規模・多施設・二重盲検 | 層別置換ブロック法(施設で層別) | 実装・監査が容易で当局にも受け入れられやすい。ブロックサイズは複数混在させる |
| 症例数が限られ、バランスさせたい予後因子が多い | 最小化法 | 層を作らずに複数因子を同時に扱える。因子・重み・割付確率をプロトコルに明記する |
| オープンラベル・PROBE試験 | 層別置換ブロック法(サイズ混在)+中央割付 | 予測可能性が選択バイアスに直結する。ブロックサイズの非開示が必須 |
| 2:1などの不均等配分 | 置換ブロック法(ブロックサイズは3の倍数) | 1:1より検出力が下がるぶん、総症例数の増加を設計に織り込む |
・層別因子は予後との関連が強いものに絞る。増やすほど層内でブロックが埋まらず、かえって不均衡が増える
・ブロックサイズは複数混在させ、プロトコル本文には書かず割付仕様書で管理する(固定サイズは72.9%読まれる)
・デザインで層別した因子は、主要解析でも共変量として調整するのが原則
・割付表の生成シードとスクリプトを記録し、盲検解除まで統計担当者以外がアクセスできない管理体制を敷く
参考書籍
ランダム化割付は、統計理論としてはシンプルでも、実務では試験デザイン全体・規制要件・オペレーションが絡み合う領域です。ここでは、割付法の理論的背景から実務上の判断まで踏み込んで学べる書籍を3冊紹介します。いずれも手元に置いて必要なときに参照するタイプの本で、プロトコルやSAPを書く場面で繰り返し役立つはずです。



まとめ
本記事では、ランダム化割付の代表的な4手法 ― 単純ランダム化、置換ブロック法、層別置換ブロック法、最小化法 ― の考え方と、それぞれのRでの実装、そしてシミュレーションによる比較を紹介しました。理論の説明だけで終わらせず、実際にRを走らせて数値で確かめることで、「なぜ実務では単純ランダム化がほとんど使われないのか」「なぜブロックサイズを混ぜるのか」が具体的に見えてきたのではないかと思います。
シミュレーションの結果を振り返ると、要点は次のように整理できます。100人規模の試験を単純ランダム化で行うと、群サイズの差は最悪28人にもなりました。50対50を前提に検出力を計算した試験で64対36になれば、検出力は設計値を下回ります。これに対して置換ブロック法では群サイズの差の平均は0.4人まで縮み、群サイズの均衡という点では完璧に近い性能を示しました。しかしその代償が予測可能性で、ブロックサイズを4に固定すると次の割付が72.9%も当たってしまいます。そして共変量バランスに目を向けると、3つの因子を使った最小化法が各水準での群間差を平均2.81人に抑え、単純ランダム化や施設のみで層別したブロック法を明確に上回りました。
つまりランダム化の方法選択とは、「群サイズの均衡」「共変量バランス」「予測可能性(選択バイアスへの耐性)」という三つ巴のトレードオフをどう引き受けるか、という判断にほかなりません。すべてを同時に最大化する魔法の手法は存在せず、試験の規模、盲検性の有無、症例登録のスピード、バランスさせたい予後因子の数によって最適解は変わります。大規模な二重盲検試験なら施設で層別した置換ブロック法で十分ですし、症例数が限られていて予後因子が多い試験なら最小化法の出番です。重要なのは、選んだ理由をプロトコルとSAPで説明できることです。
ランダム化は試験の入口にすぎません。割り付けた被験者をどの解析対象集団に含めるか、層別した因子を解析でどう扱うか、といった話が続きます。あわせてITT・FAS・PP・mITT の違いを完全整理 ― ICH E9 が定める臨床試験の解析対象集団、共変量調整(ANCOVA)徹底解説 ― FDA・EMAガイダンスとR・SASで、サブグループ解析と交互作用検定を正しく行う をお読みいただくと、デザインから解析までが一本の線でつながるはずです。本記事のコードはそのままコピーして手元で実行できますので、ご自身が担当する試験の症例数と層別因子の候補を入れて、どの手法がどれくらいのバランスをもたらすかを確かめたうえで、設計の判断に役立てていただければと思います。











