Comparison of continuous measurement methods: Bland-Altman plot

References

Load packages

## Load MethComp
library(MethComp)
## ggplot2 for plotting
library(ggplot2)
## reshape2 for melt/cast
library(reshape2)

List datasets

data(package = "MethComp")
Data sets in package ‘MethComp’:
Ancona                             Data from a rating experiment of recorgnizing point counts.
CardOutput                         Measurements of Cardiac output.
Enzyme                             Enzyme activity data
PEFR                               Peak Expiratory Flow Rate (PEFR) measurements with Wright peak flow
                                   and mini Wright peak flow meter.
VitCap                             Merits of two instruments designed to measure certain aspects of
                                   human lung function (Vital Capacity)
cardiac                            Measurement of cardiac output by two different methods.
fat                                Measurements of subcutaneous and visceral fat
glucose                            Glucose measurements by different methods
hba.MC                             A MCmcmc object from the hba1c data
hba1c                              Measurements of HbA1c from Steno Diabetes Center
milk                               Measurement of fat content of human milk by two different methods.
ox                                 Measurement of oxygen saturation in blood
ox.MC                              A MCmcmc object from the oximetry data.
plvol                              Measurements of plasma volume measured by two different methods.
rainman                            Perception of points in a swarm
sbp                                Systolic blood pressure measured by three different methods.
sbp.MC                             A MCmcmc object from the sbp data
scint                              Relative renal function by Scintigraphy

BlandAltman() function help

BlandAltman              package:MethComp              R Documentation

Bland-Altman plot of differences versus averages. Deprecated, formerly
known as BA.plot, likely to disappear from the package.

Description:

     For two vectors of equal length representing measurements of the
     same quantity by two different methods, the differences are
     plotted versus the average. The limits of agreement (prediction
     limits for the differences) are plotted, optionally a regression
     of differences of means is given too.

Systolic blood pressure measured by three different methods (sbp)

Description:
     For each subject (‘item’) there are three replicate measurements
     by three methods (two observers, J and R and the automatic
     machine, S). The replicates are linked within (method,item).
Format:
     A data frame with 765 observations on the following 4 variables:
     ‘meth’ Methods, a factor with levels ‘J’(observer 1), ‘R’(observer
          2) and ‘S’(machine)
     ‘item’ Person id, numeric.
     ‘repl’ Replicate number, a numeric vector
     ‘y’ Systolic blood pressure masurement, a numeric vector

This specific meth, item, (repl), and y format is required for the BA.plot() function

## Load data
data(sbp)
head(sbp)
##   meth item repl   y
## 1    J    1    1 100
## 2    J    2    1 108
## 3    J    3    1  76
## 4    J    4    1 108
## 5    J    5    1 124
## 6    J    6    1 122

## Plot 1st measurements by observer 1 (J), observer 2 (R) and machine (S)
plotByMeth <- ggplot(data = subset(sbp, repl == 1),
       mapping = aes(x = meth, y = y, group = item)) +
    layer(geom = "point") +
    layer(geom = "line") +
    theme_bw() +
    theme(legend.key = element_blank())
plotByMeth

plot of chunk unnamed-chunk-4


## Plot 2nd measurements by observer 1 (J), observer 2 (R) and machine (S)
plotByMeth %+% subset(sbp, repl == 2)

plot of chunk unnamed-chunk-4


## Plot 3rd measurements by observer 1 (J), observer 2 (R) and machine (S)
plotByMeth %+% subset(sbp, repl == 3)

plot of chunk unnamed-chunk-4

The two observers agree relatively well, however the machine appears different from these two observers.

sbp: Scatter plots using ggplot2 (3 replications averaged)

The oblique line is the line of agreement (y = x).

## reshape2::dcast()
sbpCast <- dcast(data          = sbp,
                 formula       = item ~ meth,
                 value.var     = "y",
                 fun.aggregate = mean
                 )
head(sbpCast)
##   item      J     R      S
## 1    1 104.33 102.3 124.67
## 2    2 108.67 110.0 125.33
## 3    3  80.67  82.0  95.67
## 4    4 105.33 105.3 129.67
## 5    5 116.00 118.0 131.67
## 6    6 128.67 130.0 139.00

## Plot: J vs R
plotScatter <- ggplot(data = sbpCast,
                      mapping = aes(x = J, y = R)) +
    layer(geom = "point") +
    layer(geom = "abline", intercept = 0, slope = 1) + 
    theme_bw() +
    theme(legend.key = element_blank())
plotScatter

plot of chunk unnamed-chunk-5

## Plot: J vs S
plotScatter + aes(x = J, y = S)

plot of chunk unnamed-chunk-5

## Plot: R vs S
plotScatter + aes(x = R, y = S)

plot of chunk unnamed-chunk-5

sbp: Bland-Altman plots

## Plot: J vs R
BA.plot(sbp, wh.comp = c("J","R"))

plot of chunk unnamed-chunk-6

## Plot: J vs S
BA.plot(sbp, wh.comp = c("J","S"))

plot of chunk unnamed-chunk-6

## Plot: R vs S
BA.plot(sbp, wh.comp = c("R","S"))

plot of chunk unnamed-chunk-6

sbp: Bias and variance components for a Bland-Altman plot.

BA.est(sbp)
## 
##  Conversion between methods:
##              alpha    beta sd.pred  LoA-lo  LoA-up
## To: From:                                         
## J   J        0.000   1.000   2.305  -4.610   4.610
##     R        0.086   1.000   2.272  -4.459   4.631
##     S      -15.620   1.000  20.326 -56.272  25.032
## R   J       -0.086   1.000   2.272  -4.631   4.459
##     R        0.000   1.000   2.187  -4.375   4.375
##     S      -15.706   1.000  20.317 -56.339  24.927
## S   J       15.620   1.000  20.326 -25.032  56.272
##     R       15.706   1.000  20.317 -24.927  56.339
##     S        0.000   1.000  12.930 -25.860  25.860
## 
##  Variance components (sd):
##     IxR    MxI   res
## J 5.887  0.338 1.630
## R 5.887  0.001 1.547
## S 5.887 18.077 9.143

ox: Measurement of oxygen saturation in blood

Description:
     61 children had their blood oxygen content measured at the
     Children's Hospital in Melbourne, either with a chemical method'
     analysing gases in the blood (‘CO’) or by a pulse oximeter
     measuring transcutaneously (‘pulse’). Replicates are linked
     between methods; i.e. replicate 1 for each of the two methods are
     done at the same time. However, replicate measurements were taken
     in quick succession so the pairs of measurements are exchangeable
     within person.
Format:
     A data frame with 354 observations on the following 4 variables.
     ‘meth’ Measurement methods, factor with levels ‘CO’, ‘pulse’
     ‘item’ Id for the child
     ‘repl’ Replicate of measurements. There were 3 measurements for
          most children, 4 had only 2 replicates with each method, one
          only 1
     ‘y’ Oxygen saturation in percent.
## Load data
data(ox)
head(ox)
##   meth item repl    y
## 1   CO    1    1 78.0
## 2   CO    1    2 76.4
## 3   CO    1    3 77.2
## 4   CO    2    1 68.7
## 5   CO    2    2 67.6
## 6   CO    2    3 68.3

## Plot 1st,2nd, and 3rd measurements by two ABG vs pulse oximeter
for(i in 1:3) {
    print(plotByMeth %+% subset(ox, repl == i))
}

plot of chunk unnamed-chunk-8 plot of chunk unnamed-chunk-8 plot of chunk unnamed-chunk-8

ox: Scatter plot using ggplot2 (3 replications averaged)

The oblique line is the line of agreement (y = x).

## reshape2::dcast()
oxCast <- dcast(data          = ox,
                formula       = item ~ meth,
                value.var     = "y",
                fun.aggregate = mean
                )
head(oxCast)
##   item    CO pulse
## 1    1 77.20 72.00
## 2    2 68.20 67.67
## 3    3 81.23 78.67
## 4    4 65.20 63.00
## 5    5 75.27 72.00
## 6    6 78.03 78.33

## Plot
plotScatter %+% oxCast + aes(x = CO, y = pulse)

plot of chunk unnamed-chunk-9

ox: Bland-Altman plots

BA.plot(ox, wh.comp = c("CO","pulse"))

plot of chunk unnamed-chunk-10

ox: Bias and variance components for a Bland-Altman plot.

BA.est(ox)
## 
##  Conversion between methods:
##                alpha    beta sd.pred  LoA-lo  LoA-up
## To:   From:                                         
## CO    CO       0.000   1.000   3.146  -6.293   6.293
##       pulse    2.470   1.000   6.169  -9.867  14.808
## pulse CO      -2.470   1.000   6.169 -14.808   9.867
##       pulse    0.000   1.000   5.649 -11.298  11.298
## 
##  Variance components (sd):
##         IxR   MxI   res
## CO    3.416 2.928 2.225
## pulse 3.416 2.928 3.994