昨天我第一次听说布兰德-奥特曼阴谋。我必须比较两种测量血压的方法,并且需要制作一个 Bland-Altman 图。我不确定我是否得到了正确的一切,所以这就是我认为我知道的:
我有两组数据。我计算它们的平均值(x 值)和它们的差值(y 值),并围绕轴 y = 差值平均值绘制它。然后,我计算差异的标准偏差,并将其绘制为“协议限制”。这是我不明白的- 什么协议的限制?通俗地说,95% 的同意是什么意思?这是否应该告诉我(假设散点图的所有点都在“协议限制”之间)方法有 95% 的匹配?
昨天我第一次听说布兰德-奥特曼阴谋。我必须比较两种测量血压的方法,并且需要制作一个 Bland-Altman 图。我不确定我是否得到了正确的一切,所以这就是我认为我知道的:
我有两组数据。我计算它们的平均值(x 值)和它们的差值(y 值),并围绕轴 y = 差值平均值绘制它。然后,我计算差异的标准偏差,并将其绘制为“协议限制”。这是我不明白的- 什么协议的限制?通俗地说,95% 的同意是什么意思?这是否应该告诉我(假设散点图的所有点都在“协议限制”之间)方法有 95% 的匹配?
你看过我在你的问题中链接的维基百科条目吗?
您没有绘制“数据的平均值”,但是对于以两种方式测量的每个数据点,您绘制两个测量值的差异 ( ) 与两个测量值的平均值 ( )。使用 R 和一些玩具数据:
> set.seed(1)
> measurements <- matrix(rnorm(20), ncol=2)
> measurements
[,1] [,2]
[1,] -0.6264538 1.51178117
[2,] 0.1836433 0.38984324
[3,] -0.8356286 -0.62124058
[4,] 1.5952808 -2.21469989
[5,] 0.3295078 1.12493092
[6,] -0.8204684 -0.04493361
[7,] 0.4874291 -0.01619026
[8,] 0.7383247 0.94383621
[9,] 0.5757814 0.82122120
[10,] -0.3053884 0.59390132
> xx <- rowMeans(measurements) # x coordinate: row-wise average
> yy <- apply(measurements, 1, diff) # y coordinate: row-wise difference
> xx
[1] 0.4426637 0.2867433 -0.7284346 -0.3097095 0.7272193 -0.4327010 0.2356194
0.8410805 0.6985013 0.1442565
> yy
[1] 2.1382350 0.2061999 0.2143880 -3.8099807 0.7954231 0.7755348 -0.5036193
0.2055115 0.2454398 0.8992897
> plot(xx, yy, pch=19, xlab="Average", ylab="Difference")
要获得一致的限制(参见 Wikipedia 页面中的“应用程序”部分),您需要计算差异的平均值和标准偏差,即标准偏差处绘制水平线。
> upper <- mean(yy) + 1.96*sd(yy)
> lower <- mean(yy) - 1.96*sd(yy)
> upper
[1] 3.141753
> lower
[1] -2.908468
> abline(h=c(upper,lower), lty=2)
(你看不到协议的上限,因为情节只上升到。)
至于剧情的解读和约定的界限,再看维基百科:
如果均值 ± 1.96 SD 内的差异在临床上不重要,则两种方法可以互换使用。
如果您想在 Python 中执行此操作,可以使用此代码
import matplotlib.pyplot as plt
import numpy as np
from numpy.random import random
%matplotlib inline
plt.style.use('ggplot')
我刚刚添加了最后一行,因为我喜欢 ggplot 样式。
def plotblandaltman(x,y,title,sd_limit):
plt.figure(figsize=(20,8))
plt.suptitle(title, fontsize="20")
if len(x) != len(y):
raise ValueError('x does not have the same length as y')
else:
for i in range(len(x)):
a = np.asarray(x)
b = np.asarray(x)+np.asarray(y)
mean_diff = np.mean(b)
std_diff = np.std(b, axis=0)
limit_of_agreement = sd_limit * std_diff
lower = mean_diff - limit_of_agreement
upper = mean_diff + limit_of_agreement
difference = upper - lower
lowerplot = lower - (difference * 0.5)
upperplot = upper + (difference * 0.5)
plt.axhline(y=mean_diff, linestyle = "--", color = "red", label="mean diff")
plt.axhline(y=lower, linestyle = "--", color = "grey", label="-1.96 SD")
plt.axhline(y=upper, linestyle = "--", color = "grey", label="1.96 SD")
plt.text(a.max()*0.85, upper * 1.1, " 1.96 SD", color = "grey", fontsize = "14")
plt.text(a.max()*0.85, lower * 0.9, "-1.96 SD", color = "grey", fontsize = "14")
plt.text(a.max()*0.85, mean_diff * 0.85, "Mean", color = "red", fontsize = "14")
plt.ylim(lowerplot, upperplot)
plt.scatter(x=a,y=b)
最后我只是做一些随机值并在这个函数中比较它们
x = np.random.rand(100)
y = np.random.rand(100)
plotblandaltman(x,y,"Bland-altman plot",1.96)
通过一些小的修改,您可以轻松添加一个 for 循环并制作多个绘图