⇦ Back

This type of regression analysis was first published in Passing & Bablok (1983)1. As the Wikipedia article states:

Passing–Bablok regression is a statistical method for non-parametric regression analysis suitable for method comparison studies.

Essentially, when two different methods are being used to take the same measurement a line of best-fit can fitted to the points. The Passing-Bablok method does this by:

The median gradient and median y-intercept create the line of best-fit. It has an associated confidence interval which can be interpreted as follows:

Let’s use the following hypothetical example dataset which comes from Giavarina (2015)2. Imagine that a set of objects were each measured twice - once using ‘Method A’ and once using ‘Method B’ - giving the two lists of measurements below:

method_a <- c(
    1.0, 5.0, 10.0, 20.0, 50.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0,
    150.0, 200.0, 250.0, 300.0, 350.0, 400.0, 450.0, 500.0, 550.0, 600.0,
    650.0, 700.0, 750.0, 800.0, 850.0, 900.0, 950.0, 1000.0
)
method_b <- c(
    8.0, 16.0, 30.0, 24.0, 39.0, 54.0, 40.0, 68.0, 72.0, 62.0, 122.0, 80.0,
    181.0, 259.0, 275.0, 380.0, 320.0, 434.0, 479.0, 587.0, 626.0, 648.0,
    738.0, 766.0, 793.0, 851.0, 871.0, 957.0, 1001.0, 960.0
)

First, let’s visualise this data:

# Make the plot square
par(pty="s")
# Scatter plot
plot(
    method_a, method_b, main = "The Raw Data",
    xlab = "Method A", ylab = "Method B",
    pch = 21, col = "black", bg="gray", xaxs = "i", yaxs = "i"
)
# Reference line
abline(0, 1, lty = "dashed")
# Include a legend
legend(0, 1000, "Reference line", lty = "dashed", cex = 0.8)

Now let’s caclulate the Passing-Bablok line of best-fit and its confidence interval. This is done using the mcreg function from the mcr package, specifying what method you want to use with method.reg = "PaBa" as below:

library(mcr)

# Comparison of two measurement methods using regression analysis
# (specifically, use the "PaBa" or Passing-Bablok method)
value <- mcreg(method_a, method_b, method.reg = "PaBa")

This yields the following result:

print(value@para)
##                EST SE       LCI      UCI
## Intercept 7.081869 NA -4.195994 19.69728
## Slope     1.055312 NA  1.026761  1.09697

The individual parameters can be separated out as follows:

intercept_est <- value@para[1]
intercept_lci <- value@para[5]
intercept_uci <- value@para[7]
gradient_est <- value@para[2]
gradient_lci <- value@para[6]
gradient_uci <- value@para[8]

sprintf("Gradient = %4.2f (%4.2f - %4.2f)", gradient_est, gradient_lci, gradient_uci)
## [1] "Gradient = 1.06 (1.03 - 1.10)"
sprintf("Intercept = %4.2f (%4.2f - %4.2f)", intercept_est, intercept_lci, intercept_uci)
## [1] "Intercept = 7.08 (-4.20 - 19.70)"

Now let’s visualise this result and how it approximates the raw data:

library(scales)

# Make the plot square
par(pty="s")
# Scatter plot
plot(
    method_a, method_b, main = "Passing-Bablok Regression",
    xlab = "Method A", ylab = "Method B",
    pch = 21, col = "black", bg="gray", xaxs = "i", yaxs = "i"
)
# Fill in colour between the confidence intervals
mylims <- par("usr")
x <- c(mylims[1], mylims[2], mylims[2], mylims[1])
y <- c(
    gradient_lci * x[1] + intercept_lci,
    gradient_lci * x[2] + intercept_lci,
    gradient_uci * x[2] + intercept_uci,
    gradient_uci * x[1] + intercept_uci
)
polygon(x, y, col = alpha("dodgerblue", 0.2))
# Reference line
abline(0, 1, lty = "dashed")
# Passing-Bablok regression lines
abline(intercept_est, gradient_est, col = "dodgerblue", lwd = 2)
abline(intercept_lci, gradient_lci, col = alpha("dodgerblue", 1))
abline(intercept_uci, gradient_uci, col = alpha("dodgerblue", 1))
# Include a legend
legend(
    0, 1000,
    c(
        "Reference line",
        sprintf("%4.2fx + %4.2f", gradient_est, intercept_est),
        sprintf("Upper CI: %4.2fx + %4.2f", gradient_uci, intercept_uci),
        sprintf("Lower CI: %4.2fx + %4.2f", gradient_lci, intercept_lci)
    ),
    lty = c("dashed", "solid", "solid", "solid"),
    lwd = c(1, 2, 1, 1),
    col = c("black", "dodgerblue", alpha("dodgerblue", 1), alpha("dodgerblue", 1)),
    cex = 0.8
)

References

1Passing H, Bablok W (1983). “A new biometrical procedure for testing the equality of measurements from two different analytical methods. Application of linear regression procedures for method comparison studies in Clinical Chemistry, Part I”. Journal of Clinical Chemistry and Clinical Biochemistry. 21 (11): 709–20. doi: 10.1515/cclm.1983.21.11.709. PMID: 6655447
2Giavarina D (2015). “Understanding Bland Altman analysis”. Biochemia Medica. 25 (2):141-151. doi: 10.11613/BM.2015.015.

⇦ Back