ブランド・アルトマンプロット

2 人のコーダーは政党の選挙綱領を左右軸上に同じように位置づけるか?バイアスと 95% 一致限界。

ブランド・アルトマンプロット

2 つの測定器 — あるいは 2 人のコーダー — が同じものを測るとき、高い相関は両者が一致しているかどうかについて何も語りません。ブランド・アルトマンプロットは、方法間の差を縦軸に、その平均を横軸にとります。中央の線は差の平均(系統的バイアス)、外側の線は 95% の一致限界(バイアス ± 1.96 SD)で、ほとんどの不一致はその内側に収まります。網掛けの帯はこれら 3 本の線の 95% 信頼区間で、Bland & Altman (1986) の標準誤差を用いています。点群に傾きがあれば比例バイアスを示唆します。

データは内容分析の典型的なチェックを模して numpy(シード固定)でシミュレーションしたものです。訓練を受けた 2 人のコーダーが同じ 80 本の政党綱領をそれぞれ 0〜10 の左右尺度に位置づけ、コーダー B はコーダー A より約 0.4 ポイント右寄りになるよう設定しています。バイアスと区間は scipy.stats.t、傾きの検定は statsmodels の OLS によります。

コードおよび図中のテキストは英語です。

bland-altman.py · 44 行
ダウンロード GitHub
import matplotlib.pyplot as plt
import numpy as np
import statsmodels.api as sm
from scipy import stats

# Simulated coding: 80 manifestos placed on a 0–10 left–right scale by two coders;
# coder B leans ~0.4 points to the right and is a little noisier
rng = np.random.default_rng(11)
n = 80
position = rng.uniform(1.5, 8.5, n)
coder_a = position + rng.normal(0, 0.35, n)
coder_b = position + 0.4 + rng.normal(0, 0.45, n)

mean, diff = (coder_a + coder_b) / 2, coder_b - coder_a
bias, sd = diff.mean(), diff.std(ddof=1)
loa = bias + np.array([-1.96, 1.96]) * sd
t = stats.t.ppf(0.975, n - 1)
ci_bias = t * sd / np.sqrt(n)            # half-width of the CI for the bias
ci_loa = t * np.sqrt(3 * sd**2 / n)      # Bland & Altman (1986) SE of a limit
slope = sm.OLS(diff, sm.add_constant(mean)).fit()

fig, ax = plt.subplots(figsize=(8, 5))
for y0, hw, c in [(bias, ci_bias, "#007AFF"), (loa[0], ci_loa, "#FF9500"), (loa[1], ci_loa, "#FF9500")]:
    ax.axhspan(y0 - hw, y0 + hw, color=c, alpha=0.12, lw=0)
    ax.axhline(y0, color=c, lw=1.6, ls="-" if c == "#007AFF" else "--")
ax.axhline(0, color="#8E8E93", lw=0.8)
ax.scatter(mean, diff, s=30, color="#3A3A3C", alpha=0.7, edgecolor="white", lw=0.6, zorder=3)

# Labels on the right margin
x_lab = mean.max() + 0.3
for y0, name, c in [(loa[1], "+1.96 SD", "#FF9500"), (bias, "Bias", "#007AFF"),
                    (loa[0], "−1.96 SD", "#FF9500")]:
    ax.text(x_lab, y0, f"{name}\n{y0:+.2f} pts".replace("-", "−"), va="center", ha="left", fontsize=9,
            color=c, fontweight="semibold", linespacing=1.3)

ax.set_xlim(mean.min() - 0.2, mean.max() + 1.3)
ax.set_xlabel("Mean left–right position of the two coders (0–10 scale)")
ax.set_ylabel("Coder B − coder A (points)")
ax.set_title(f"Coder B sits {bias:.2f} points further right; single codings differ "
             f"by up to ±{1.96 * sd:.1f}", pad=26)
ax.text(0, 1.02, f"Simulated · n = {n} manifestos · bias {bias:.2f} [95% CI {bias - ci_bias:.2f}, "
        f"{bias + ci_bias:.2f}] · LoA {loa[0]:.2f} to {loa[1]:.2f} · proportional bias: slope = {slope.params[1]:.3f}, "
        f"p = {slope.pvalues[1]:.2f}", transform=ax.transAxes, fontsize=9.5, color="#6E6E73")
plt.show()

図にはオプションの PyStatlas スタイル を使用しています。同じ見た目にするには plt.style.use("pystatlas.mplstyle") を追加してください。

データの出典

  • Simulated data. Simulated data with a fixed random seed, created for this example.
    No real respondents, documents or measurements: the numbers only illustrate how the chart and its statistics work.

これらの例は統計手法を説明するためのものです。図のタイトルは、この特定のデータ(多くは小規模で、古く、部分的な標本)で図が示す内容を述べたものであり、実質的な問いに対する著者の立場ではありません。解釈、背景、データの質については、ここに挙げた元の出典を参照してください。

引用方法

PyStatlas は Thierry Warin が作成・運営しています。研究や業務に役立った場合は、ぜひ引用してください。

Warin, T. (2026). Bland–Altman plot. In PyStatlas: A Python Gallery of Statistical Graphics for the Social Sciences. https://warint.github.io/pystatlas/inference-uncertainty/bland-altman/

@misc{warin2026statlas,
  author       = {Warin, Thierry},
  title        = {PyStatlas: A Python Gallery of Statistical Graphics for the Social Sciences},
  year         = {2026},
  howpublished = {\url{https://warint.github.io/pystatlas/}},
  note         = {Source code: https://github.com/warint/pystatlas}
}

推測と不確実性のその他のグラフ