开发出一种更快、更便宜的新测量方法后,我们常会把它与原方法放在一起计算相关系数。如果相关系数接近 1,看起来似乎可以宣布两种方法“高度一致”。但相关性回答的是两个变量是否一起变化,一致性关心的却是同一个对象被两种方法测量时,数值究竟相差多少。
假如一种设备总比另一种高 10 个单位,两者仍可能拥有接近完美的相关性;如果这种差异还会随测量水平增大,简单相关图就更容易给人错误的安全感。
本期用 Python 构造一组配对测量数据,先画常见的相关散点图,再绘制 Bland–Altman 一致性图。两张图放在一起,能够清楚地区分“变化趋势相似”和“结果可以互换”这两个完全不同的问题。
我们模拟 240 名对象分别接受 Method A 与 Method B 测量。两种方法都追踪同一个潜在真实值,但 Method B 带有固定偏高、随测量水平增加的比例偏倚,以及略为扩大的随机波动。
分析的目标不是证明某种设备优于另一种设备,而是演示三个判断:相关系数是否足以评价一致性,两种方法之间是否存在系统偏倚,以及个体差值的范围能否落在事先规定的实际容许界限内。
Bland–Altman 图把每对测量的平均值放在横轴,把两种方法的差值放在纵轴。本例统一定义差值为“Method B减Method A”,因此正值表示 Method B 测得更高。差值的均值称为平均偏倚,表示两种方法整体上相差多少。
在差值近似正态、各对象相互独立且差值波动大致稳定时,可以用“平均偏倚 ± 1.96 × 差值标准差”计算 95% 一致性界限。它描述的是大多数个体差值可能落入的范围,不是平均偏倚的 95% 置信区间,也不意味着界限内的差异一定可以接受。
是否“足够一致”必须依赖专业领域预先确定的容许误差。本例仅为演示,将 ±12 个单位设为实际容许界限。如果统计一致性界限明显宽于它,或者大量个体差值超出它,即使相关系数很高,也不应直接认为两种方法可以互换。
数据由 NumPy 固定随机种子模拟。潜在真实值均匀分布在 40 至 180 之间,Method A 加入较小的随机误差;Method B 在真实值基础上加入固定偏移、比例偏移和随测量水平增大的随机误差。所有数字只用于讲解方法,不代表真实仪器性能。
完整流程分为三步:先生成配对数据并计算相关系数;再绘制两种方法的散点图,同时比较拟合线与完全一致线;最后计算平均偏倚和一致性界限,绘制 Bland–Altman 图,并与预设的实际容许界限比较。
import numpy as npimport pandas as pdimport matplotlib# 使用无界面绘图后端,便于稳定保存本次生成的PNGmatplotlib.use(”Agg”)import matplotlib.pyplot as plt# 固定随机种子,模拟240名对象接受两种连续测量方法RANDOM_STATE = 20260721rng = np.random.default_rng(RANDOM_STATE)n = 240true_value = rng.uniform(40, 180, size=n)method_a = true_value + rng.normal(0, 3.0, size=n)method_b = 3.0 + 1.06 * true_value + rng.normal(0, 4.0 + 0.03 * true_value, size=n)# 将配对结果整理成表,并计算后续一致性分析所需变量data = pd.DataFrame({”Method A”: method_a, ”Method B”: method_b})data[”Pair mean”] = data[[”Method A”, ”Method B”]].mean(axis=1)data[”Difference B-A”] = data[”Method B”] - data[”Method A”]correlation = data[”Method A”].corr(data[”Method B”])print(f”配对样本量: {len(data)}”)print(f”Method A均值: {data['Method A'].mean():.2f}”)print(f”Method B均值: {data['Method B'].mean():.2f}”)print(f”Pearson相关系数: {correlation:.3f}”)
输出:
配对样本量: 240Method A均值: 109.46Method B均值: 118.46Pearson相关系数: 0.980
两种方法的相关系数达到 0.980,说明对象在 Method A 中测得较高时,通常也会在 Method B 中测得较高。但 Method B 的总体均值比 Method A 高约 9 个单位,已经提示高相关没有消除系统差异。
# 先画两种方法的相关散点图,并加入完全一致的45度参考线fig, ax = plt.subplots(figsize=(7.6, 6.2))ax.scatter(data[”Method A”], data[”Method B”],s=32, alpha=0.68, color=”#2A6F97”, edgecolors=”white”, linewidths=0.35)plot_min = min(data[”Method A”].min(), data[”Method B”].min()) - 5plot_max = max(data[”Method A”].max(), data[”Method B”].max()) + 5ax.plot([plot_min, plot_max], [plot_min, plot_max], ”--”, color=”#D1495B”, linewidth=2,label=”Perfect agreement”)# 用线性拟合概括两方法的关联,但不把拟合优度解释为一致性slope, intercept = np.polyfit(data[”Method A”], data[”Method B”], 1)x_line = np.array([plot_min, plot_max])ax.plot(x_line, intercept + slope * x_line, color=”#1B4332”, linewidth=2,label=”Fitted relationship”)ax.set_xlim(plot_min, plot_max)ax.set_ylim(plot_min, plot_max)ax.set_aspect(”equal”, adjustable=”box”)ax.set_title(”High Correlation Does Not Guarantee Agreement”, loc=”left”)ax.set_xlabel(”Method A”)ax.set_ylabel(”Method B”)ax.grid(alpha=0.18)ax.legend()fig.tight_layout()fig.savefig(”python_method_correlation.png”, dpi=180, bbox_inches=”tight”)plt.close(fig)# 输出拟合关系与绝对误差,检查散点是否系统偏离45度线mae = np.mean(np.abs(data[”Difference B-A”]))rmse = np.sqrt(np.mean(data[”Difference B-A”] ** 2))print(f”拟合截距: {intercept:.2f}”)print(f”拟合斜率: {slope:.3f}”)print(f”平均绝对差: {mae:.2f}”)print(f”均方根差: {rmse:.2f}”)
输出:
拟合截距: 3.33拟合斜率: 1.052平均绝对差: 10.39均方根差: 12.38

绿色拟合线与红色 45 度完全一致线并不重合。拟合截距为 3.33、斜率为 1.052,说明 Method B 不仅整体偏高,差距还可能随测量水平扩大。散点排列得很紧密,所以相关系数很高;但它们系统地位于完全一致线之上,因此不能据此宣称两种方法一致。
# 按B减A定义差值,计算平均偏倚和95%一致性界限differences = data[”Difference B-A”].to_numpy()pair_means = data[”Pair mean”].to_numpy()bias = differences.mean()sd_diff = differences.std(ddof=1)lower_loa = bias - 1.96 * sd_diffupper_loa = bias + 1.96 * sd_diff# 拟合差值与配对均值的关系,用来识别可能的比例偏倚trend_slope, trend_intercept = np.polyfit(pair_means, differences, 1)trend_x = np.array([pair_means.min(), pair_means.max()])trend_y = trend_intercept + trend_slope * trend_xpractical_limit = 12# 绘制Bland-Altman图,同时标出统计界限和预设实际容许界限fig, ax = plt.subplots(figsize=(8.8, 6.1))ax.scatter(pair_means, differences, s=31, alpha=0.68,color=”#3A86A8”, edgecolors=”white”, linewidths=0.35)ax.axhline(bias, color=”#1B4332”, linewidth=2, label=f”Bias = {bias:.2f}”)ax.axhline(lower_loa, color=”#D1495B”, linestyle=”--”, linewidth=2,label=”95% limits of agreement”)ax.axhline(upper_loa, color=”#D1495B”, linestyle=”--”, linewidth=2)ax.axhline(-practical_limit, color=”#6C757D”, linestyle=”:”, linewidth=1.7,label=”Practical limits (+/-12)”)ax.axhline(practical_limit, color=”#6C757D”, linestyle=”:”, linewidth=1.7)ax.plot(trend_x, trend_y, color=”#FFB703”, linewidth=2.2,label=”Difference trend”)ax.set_title(”Bland-Altman Plot for Two Measurement Methods”, loc=”left”)ax.set_xlabel(”Mean of Method A and Method B”)ax.set_ylabel(”Difference: Method B - Method A”)ax.grid(alpha=0.18)ax.legend(loc=”upper left”, frameon=True)fig.tight_layout()fig.savefig(”python_bland_altman.png”, dpi=180, bbox_inches=”tight”)plt.close(fig)# 汇总界限外比例和实际不可接受比例,避免只凭图形下结论outside_loa = np.mean((differences < lower_loa) | (differences > upper_loa))outside_practical = np.mean(np.abs(differences) > practical_limit)print(f”平均偏倚(B-A): {bias:.2f}”)print(f”差值标准差: {sd_diff:.2f}”)print(f”95%一致性界限: [{lower_loa:.2f}, {upper_loa:.2f}]”)print(f”界限外观测比例: {outside_loa:.1%}”)print(f”超出±12实际界限比例: {outside_practical:.1%}”)print(f”差值趋势斜率: {trend_slope:.3f}”)
输出:
平均偏倚(B-A): 8.99差值标准差: 8.5295%一致性界限: [-7.71, 25.70]界限外观测比例: 5.4%超出±12实际界限比例: 37.1%差值趋势斜率: 0.071

绿色实线显示 Method B 平均比 Method A 高 8.99 个单位,红色虚线给出的 95% 一致性界限为 -7.71 至 25.70。也就是说,对单个对象而言,Method B 既可能比 Method A 低约 8 个单位,也可能高约 26 个单位。这个范围明显超出灰色点线表示的 ±12 实际容许界限。
本例最直观的反差是:Pearson相关系数高达 0.980,但仍有 37.1% 的配对差值超出预设的 ±12 实际界限。相关系数只说明两种方法能够较好地区分高值与低值对象,不能保证它们为同一个对象给出足够接近的数字。
平均偏倚为正,说明 Method B 存在整体高估。黄色差值趋势线的斜率为 0.071,意味着配对均值每增加 10 个单位,预计差值约增加 0.71 个单位,提示比例偏倚。图中右侧差值的纵向离散也略有扩大,与模拟时设置的异方差相符。
5.4% 的点位于计算得到的一致性界限之外,这一比例接近公式设计下的 5%,却不能证明方法合格。真正重要的是界限本身是否足够窄,以及它是否落在专业上可接受的范围内。本例上限达到 25.70,因此即使大多数点位于红线之间,也无法满足 ±12 的演示标准。
简单 Bland–Altman 界限依赖差值近似正态、方差大致稳定和观测相互独立等条件。本图已经提示差值随水平变化,真实分析中可考虑对数变换、基于比例的界限或回归型 Bland–Altman 方法;如果每名对象有重复测量,还需要处理对象内相关,不能把所有记录当作独立配对直接套用本例公式。
比较两种连续测量方法时,相关散点图与 Bland–Altman 图回答的是不同问题。前者展示共同变化和偏离完全一致线的方向,后者直接展示个体差值、平均偏倚、一致性范围以及差值是否随测量水平变化。
可靠的判断不能停在“相关系数很高”,也不能只检查约 95% 的点是否位于一致性界限内。应当在分析前明确实际容许误差,再判断平均偏倚和一致性界限是否满足应用要求,同时检查比例偏倚、异方差、异常点与重复测量结构。
本例使用模拟数据,结论只说明这组代码设定下的现象。换成真实设备或量表时,±12 必须替换为有专业依据的阈值,并结合一致性界限的不确定性和研究设计共同报告。