Measurement agreement and validity Bland-Altman in R

Introduction

The Bland-Altman plot is a fundamental concept in method comparison studies within biostatistics and measurement validity analysis.
- Purpose: It is used to assess agreement between two different methods of measuring the same thing
- Widely used in: Medical research and biostatistics.

This article demonstrates the Bland-Altman method using both manual approaches and libraries in R.

Let us create a demo dataset

# Generate random demo data for two devices
set.seed(123)  # For reproducibility
n <- 100
A_Device <- rnorm(n, mean = 100, sd = 10)  # Device A measurements
B_Device <- A_Device + rnorm(n, mean = 0, sd = 5)  # Device B with slight measurement variability

data <- data.frame(A_Device, B_Device)
head(data)
   A_Device  B_Device
1  94.39524  90.84321
2  97.69823  98.98264
3 115.58708 114.35362
4 100.70508  98.96737
5 101.29288  96.53478
6 117.15065 116.92551

Method 1: Manual

# Calculate the means and differences
data$Mean <- (data$A_Device + data$B_Device) / 2
data$Difference <- data$A_Device - data$B_Device

# Calculate the mean difference and limits of agreement
mean_diff <- mean(data$Difference)
sd_diff <- sd(data$Difference)
loa_upper <- mean_diff + 1.96 * sd_diff # typically set at ± 1.96 standard deviations from the mean difference
loa_lower <- mean_diff - 1.96 * sd_diff

# Plot Bland-Altman plot
plot(data$Mean, data$Difference, 
     xlab = "Mean of A and B", 
     ylab = "Difference (A - B)", 
     main = "Bland-Altman Plot", 
     pch = 19, col = "blue")
abline(h = mean_diff, col = "red", lwd = 2, lty = 2)  # Mean difference
abline(h = loa_upper, col = "darkgreen", lwd = 2, lty = 2)  # Upper limit
abline(h = loa_lower, col = "darkgreen", lwd = 2, lty = 2)  # Lower limit

Method 2: BlandAltmanLeh

# Install and load the package
# install.packages("BlandAltmanLeh")
library(BlandAltmanLeh)

# Bland-Altman plot using the library
plot_object <- bland.altman.plot(A_Device, B_Device, 
                                 xlab = "Mean of A and B", 
                                 ylab = "Difference (A - B)",
                                 main = "Bland-Altman Plot (BlandAltmanLeh)")

Method 3: blandr

# Install and load the blandr package
# install.packages("blandr")
library(blandr)
library(ggplot2)

# Automated Bland-Altman plot
ba_plot <- blandr.draw(A_Device, B_Device, 
            plotTitle = "Bland-Altman Plot (blandr)")


# Customize the plot (e.g., change axis labels using ggplot2)
ba_plot + labs(title = "Bland-Altman Plot (blandr)", 
               x = "Mean of A and B", 
               y = "Difference (A - B)")

How to Read a Bland-Altman Plot

  1. X-axis: Shows the mean of the two measurements.
  2. Y-axis: Shows the difference between the two measurements.
  3. Central Line: Represents the mean difference; zero means no bias.
  4. Limits of Agreement: The upper and lower lines show the range of acceptable differences.
  5. Outliers: Points outside the limits indicate discrepancies between methods.

Summary of How to Read the Plot:

  • Close to zero mean difference: Minimal bias. If the mean difference is close to zero, it means that on average, both devices are producing similar results, without one consistently overestimating or underestimating the true value. This indicates that there is little or no systematic error (bias) between the devices.
  • Points within limits: Good agreement between the two devices.
  • Outliers outside limits: Discrepancies or errors.
  • Wider spread: Larger disagreement.

Summary of Methods