比率データのアークサインルート変換とは何か?
比率のデータに対するアークサインルート変換 (arcsin√x)は分散を安定化する上で有効ですが、現在では主流ではありません。それでも、不思議で面白い変換だと思います。
二項分布と比率
独立な試行を$${n}$$回繰り返した時、その成功数$${x}$$は二項分布に従います。二項分布の平均は$${\mu = np}$$, 分散は$${\sigma^2 = np(1-p)}$$です。
つまり、平均が大きくなると分散も大きくなることになります。$${n = 100, p = 0.1}$$のとき平均と分散はそれぞれ10と9ですが、$${p = 0.5}$$のときはそれぞれ25と25となります。
変な喩えですが、私が色々なプロボクサーに挑み続けたとき、負けがずっと続くでしょう。つまり、「勝つ」という事象がめったに起こらない(母比率が低い)場合のばらつきは小さいのです。
試行数$${n}$$に占める割合(比率)$${x_p}$$に換算した場合、分散の公式を使って$${\sigma^2(x_p) = \sigma^2(x/n) = \sigma^2(x)/n^2 = p(1-p)/n}$$となります。やはり、母比率によって平均と分散が変わってしまいます。正規分布では平均と分散が独立のパラメータとして設定されているので、このようなことは起こりません。
比率のデータをt検定や分散分析をする際にはこの問題があります。これを補正するため、かつてはアークサインルート変換がよく使われました。単純に、比率データ$${x_p}$$を以下のように変数変換するだけです。
$${x_a = arcsin\sqrt x_p}$$
ここで$${arcsin}$$(逆正弦)は$${sin}$$の逆関数で、$${sin(\theta)}$$からから角度$${\theta}$$を求める関数です。難しそうですが、現代では面倒な計算はパソコンがやってくれます。
この変換により、大きな標本サイズのもとで$${x_a}$$の分散は$${1/(4n)}$$に近づきます。この変換後の値を使って検定をするというものです。
GLM(一般化線形モデル)が主流となった現在では知らない方も多いでしょうが、私の院生時代だった1990年代後半でもまだ使われていました。
変換による分散の安定化(コード1)
アークサインルート変換により、中程度の母比率では分散は安定します。
以下の青線は二項分布から得られた比率の分散をシミュレートしたものです(試行数 $${n = 100}$$、10,000反復の分散)。青が比率データからそのまま分散を求めた曲線、赤がデータを変数変換して分散を求めたものです。

母比率が極端でない限り、分散は期待される1/400に近くなりました。効果は絶大ですね!
試行数の影響(コード2)
シミュレーションにより比率データを生成し、その分布を可視化しました(二項分布、1,000反復)。
それぞれの図について、試行数$${n}$$が 20(青)および 200(赤)の場合を示しています。$${n = 20}$$の場合は明らかにばらつきが大きくなることがわかります。
上段の2つは比率データそのもの、下段はアークサインルート変換後の値です。左の列は母比率$${p = 0.1}$$, 右の列は$${p = 0.5}$$に対応しています。図の中のVは分散を示しています。変換後の範囲は$${[0, \pi/2]}$$であることに注意してください。

生データ(上段)では、試行数および母比率の両方に依存して分散が変化していることがわかります。特に$${n = 20}$$の場合には、母比率が0.5の場合には顕著にばらつきが大きくなります。一方、$${n = 200}$$ の場合にはばらつきは全体的に小さくなるものの、同様の傾向が見られます。
一方、アークサインルート変換をした場合(下段)は、分散に対する母比率の影響は緩和され、母比率が大きくなっても生データほどばらつきに違いはありません。とくに試行数の大きい $${n = 200}$$ の場合は分散が互いに近い値となります。
使われなくなった背景
現在は、以下の理由でアークサインルート変換はあまり使われなくなりました。
0や1付近での効果は薄い:データをとっていると、平均が0や1に近い場合がありますが、このときは変数変換しても効果はありません。このようなケースは実験でしばしば生じます(悪い餌条件における生存率など)。
割り算による情報のロス:比率データにする場合、10/20も100/200も同じ0.5というデータ点になります。しかし、これらは推定値の信頼性が大きく異なるため、本来は同じデータ点として扱うべきではありません。データの重みを活かした解析が望ましいと思われます。
アークサインルート変換は二項分布を土台とする理論なので、母集団が別の分布に従う場合の変換の効果は個別に検討する必要があります。実際、過分散(理論値より分散が大)のデータは農学や生態学では普通です。
統計ソフトとGLMの普及:GLMでは、二項分布そのものを仮定することで、平均と分散の関係をモデル内で適切に扱えるため、変換による近似に頼る必要がなくなりました。また、その他の様々な分布を扱えるようになりました。
まとめ
変数変換によって分散が安定するという先人の発見は偉大なものです。それを踏まえつつ、PCでお手軽に統計解析ができる時代には、データの情報を重視した方法が使えます。現代では変数変換に頼るよりも、二項分布やその他の分布を仮定したGLMなどを用いる方が合理的といえるでしょう。
コード
コード1:分散の安定化
# Arcsin-root transformation
# 2026-04-01
rm (list = ls())
nrep <- 10000 # シミュレーション反復数
n <- 100 # 標本数
p.v <- seq(0, 1, 0.1) # 母比率ベクトル
var.raw <- as.numeric(length(p.v)) # 推定した分散 (raw data)
var.arc <- as.numeric(length(p.v)) # 推定した分散 (arcsin-root transformed)
for (i in 1:11){
p <- p.v[i]
x <- rbinom (nrep, size = n, prob = p)/n
var.raw[i] <- var(x)
z <- asin(sqrt(x))
var.arc[i] <- var(z)
}
names(var.raw) <- p.v
var.raw
names(var.arc) <- p.v
var.arc
# Plot
par (cex = 1.2)
plot(p.v, var.raw, type="b", col="blue", ylim=c(0, max(var.raw, var.arc)),
ylab="Variance", xlab="p")
lines(p.v, var.arc, type="b", col="red")
legend("bottom", legend=c("Raw (x)", "Transformed (asin(sqrt(x)))"),
col=c("blue", "red"), pch=1)
コード2:試行数の影響
# GLM vs arcsin comparison (fixed x-axis)
set.seed(123)
n <- c(20, 200)
p.vec <- c(0.1, 0.5)
par(mfrow=c(2,2), mar=c(4,4,2,1))
# --- 1行目:raw ---
for(p in p.vec){
x1 <- rbinom(1000, n[1], p)
x2 <- rbinom(1000, n[2], p)
prop1 <- x1 / n[1]
prop2 <- x2 / n[2]
v1 <- var(prop1)
v2 <- var(prop2)
d1 <- density(prop1, from=0, to=1)
d2 <- density(prop2, from=0, to=1)
plot(d1, col="blue",
main=paste("Raw (p =", p, ")"),
xlab="p",
xlim=c(0,1),
ylim=c(0, max(d1$y, d2$y)))
lines(d2, col="red")
legend("topright",
legend=c(
paste0("n=20, V=", sprintf("%.4f", v1)),
paste0("n=200, V=", sprintf("%.4f", v2))
),
col=c("blue","red"), lty=1, bty="n")
}
# --- 2行目:arcsin ---
for(p in p.vec){
x1 <- rbinom(1000, n[1], p)
x2 <- rbinom(1000, n[2], p)
prop1 <- x1 / n[1]
prop2 <- x2 / n[2]
z1 <- asin(sqrt(prop1))
z2 <- asin(sqrt(prop2))
v1 <- var(z1)
v2 <- var(z2)
d1 <- density(z1, from=0, to=pi/2)
d2 <- density(z2, from=0, to=pi/2)
plot(d1, col="blue",
main=paste("Arcsin (p =", p, ")"),
xlab="value",
xlim=c(0, pi/2),
ylim=c(0, max(d1$y, d2$y)))
lines(d2, col="red")
legend("topright",
legend=c(
paste0("n=20, V=", sprintf("%.4f", v1)),
paste0("n=200, V=", sprintf("%.4f", v2))
),
col=c("blue","red"), lty=1, bty="n")
}
