knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 6, fig.height = 4, fig.align = "center" )
Deming regression is a method for fitting a linear relationship when both variables are measured with error. Unlike ordinary least squares (OLS), which assumes the independent variable is measured without error, Deming regression accounts for measurement uncertainty in both the reference and test methods. This makes it particularly appropriate for method comparison studies in clinical laboratories.
This vignette introduces the theory behind Deming regression, demonstrates its use with the valytics package, and provides guidance on when to choose Deming regression over alternatives like Passing-Bablok regression.
library(valytics) library(ggplot2)
When comparing two analytical methods, a common approach is to regress the test method (Y) on the reference method (X) using OLS. However, OLS assumes that X is measured without error --- an assumption that rarely holds in practice.
When both X and Y contain measurement error, OLS produces biased estimates:
This phenomenon, known as regression dilution or attenuation bias, can lead to incorrect conclusions about method agreement.
set.seed(42) # True relationship: Y = 1.0 * X (perfect agreement) true_values <- seq(50, 150, length.out = 100) # Both methods have measurement error x_observed <- true_values + rnorm(100, sd = 10) y_observed <- true_values + rnorm(100, sd = 10) # Compare OLS vs Deming ols_fit <- lm(y_observed ~ x_observed) dm_fit <- deming_regression(x_observed, y_observed) # Visualize df <- data.frame(x = x_observed, y = y_observed) ggplot(df, aes(x = x, y = y)) + geom_point(alpha = 0.5) + geom_abline(intercept = 0, slope = 1, linetype = "solid", color = "gray50", linewidth = 1) + geom_abline(intercept = coef(ols_fit)[1], slope = coef(ols_fit)[2], color = "red", linewidth = 0.8) + geom_abline(intercept = dm_fit$results$intercept, slope = dm_fit$results$slope, color = "blue", linewidth = 0.8) + annotate("text", x = 60, y = 145, label = "True (slope = 1)", color = "gray30") + annotate("text", x = 60, y = 138, label = sprintf("OLS (slope = %.3f)", coef(ols_fit)[2]), color = "red") + annotate("text", x = 60, y = 131, label = sprintf("Deming (slope = %.3f)", dm_fit$results$slope), color = "blue") + labs(title = "Attenuation Bias in OLS Regression", x = "Method X", y = "Method Y") + theme_minimal()
Notice how the OLS slope is attenuated (less than 1), while Deming regression recovers a slope closer to the true value of 1.
Deming regression minimizes the sum of squared perpendicular distances from points to the regression line, weighted by the error variance ratio. The model assumes:
$$Y_i = \alpha + \beta X_i^ + \epsilon_i$$ $$X_i = X_i^ + \delta_i$$
where $X_i^*$ is the true (unobserved) value, and $\epsilon_i$ and $\delta_i$ are measurement errors in Y and X respectively.
The key parameter in Deming regression is the error ratio (lambda, λ):
$$\lambda = \frac{\text{Var}(\epsilon)}{\text{Var}(\delta)} = \frac{\text{Var(error in Y)}}{\text{Var(error in X)}}$$
When λ = 1, both methods have equal error variance, and Deming regression becomes orthogonal regression (also called total least squares). This minimizes perpendicular distances to the line.
The error ratio can be determined by:
The deming_regression() function follows the same interface as other valytics functions:
# Load example data data("glucose_methods") # Deming regression with default settings (lambda = 1) dm <- deming_regression(reference ~ poc_meter, data = glucose_methods) dm
The output shows:
The summary() method provides comprehensive output:
summary(dm)
The plot() method creates publication-ready figures:
plot(dm)
Examine residuals to check model assumptions:
plot(dm, type = "residuals")
Look for:
When methods have different precision, specify the error ratio:
# If POC meter has twice the error variance of the reference dm_lambda2 <- deming_regression( reference ~ poc_meter, data = glucose_methods, error_ratio = 2 ) dm_lambda2
If you know the coefficients of variation from method validation:
# Example: Reference CV = 2.5%, POC CV = 4.5% cv_reference <- 0.025 cv_poc <- 0.045 lambda_estimated <- (cv_poc / cv_reference)^2 # lambda_estimated = 3.24 dm_cv <- deming_regression( reference ~ poc_meter, data = glucose_methods, error_ratio = lambda_estimated )
Two methods are available for computing confidence intervals:
The jackknife method, following Linnet (1990), provides robust standard error estimates:
dm_jack <- deming_regression( reference ~ poc_meter, data = glucose_methods, ci_method = "jackknife" ) # Standard errors are available cat("Slope SE:", round(dm_jack$results$slope_se, 4), "\n") cat("Intercept SE:", round(dm_jack$results$intercept_se, 4), "\n")
For smaller samples or when parametric assumptions are questionable:
dm_boot <- deming_regression( reference ~ poc_meter, data = glucose_methods, ci_method = "bootstrap", boot_n = 1999 )
Both Deming and Passing-Bablok regression are appropriate for method comparison, but they have different characteristics:
| Aspect | Deming | Passing-Bablok | |-------------------------|----------------------|----------------------------| | Approach | Parametric | Non-parametric | | Error assumption | Normally distributed | Distribution-free | | Outlier sensitivity | Sensitive | Robust | | Error ratio | User-specified (λ) | Implicitly assumes equal | | Sample size | Works with smaller n | Needs \~30+ for stable CIs | | Ties | Handles ties | Can be affected by ties |
# Fit both models dm <- deming_regression(reference ~ poc_meter, data = glucose_methods) pb <- pb_regression(reference ~ poc_meter, data = glucose_methods) # Compare coefficients comparison <- data.frame( Method = c("Deming", "Passing-Bablok"), Slope = c(dm$results$slope, pb$results$slope), Slope_Lower = c(dm$results$slope_ci["lower"], pb$results$slope_ci["lower"]), Slope_Upper = c(dm$results$slope_ci["upper"], pb$results$slope_ci["upper"]), Intercept = c(dm$results$intercept, pb$results$intercept), Int_Lower = c(dm$results$intercept_ci["lower"], pb$results$intercept_ci["lower"]), Int_Upper = c(dm$results$intercept_ci["upper"], pb$results$intercept_ci["upper"]) ) print(comparison, digits = 3)
# Visual comparison ggplot(glucose_methods, aes(x = reference, y = poc_meter)) + geom_point(alpha = 0.6) + geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "gray50") + geom_abline(intercept = dm$results$intercept, slope = dm$results$slope, color = "#2166AC", linewidth = 1) + geom_abline(intercept = pb$results$intercept, slope = pb$results$slope, color = "#B2182B", linewidth = 1) + annotate("text", x = 80, y = 340, label = "Identity", color = "gray50") + annotate("text", x = 80, y = 320, label = "Deming", color = "#2166AC") + annotate("text", x = 80, y = 300, label = "Passing-Bablok", color = "#B2182B") + labs(title = "Regression Method Comparison", x = "Reference (mg/dL)", y = "POC Meter (mg/dL)") + theme_minimal()
Here is a complete method comparison workflow using the creatinine dataset:
# Load data data("creatinine_serum") # 1. Deming regression dm <- deming_regression(enzymatic ~ jaffe, data = creatinine_serum) # 2. View summary summary(dm)
# 3. Create visualization plot(dm, title = "Creatinine: Jaffe vs Enzymatic Method")
# 4. Check residuals plot(dm, type = "residuals")
For further analysis or reporting, extract components from the result object:
# Coefficients slope <- dm$results$slope intercept <- dm$results$intercept # Confidence intervals slope_ci <- dm$results$slope_ci intercept_ci <- dm$results$intercept_ci # Standard errors slope_se <- dm$results$slope_se intercept_se <- dm$results$intercept_se # Formatted output for reporting cat(sprintf("Slope: %.4f (95%% CI: %.4f to %.4f)\n", slope, slope_ci["lower"], slope_ci["upper"])) cat(sprintf("Intercept: %.4f (95%% CI: %.4f to %.4f)\n", intercept, intercept_ci["lower"], intercept_ci["upper"]))
Cornbleet PJ, Gochman N. Incorrect least-squares regression coefficients in method-comparison analysis. Clinical Chemistry. 1979;25(3):432-438.
Linnet K. Estimation of the linear relationship between the measurements of two methods with proportional errors. Statistics in Medicine. 1990;9(12):1463-1473.
Linnet K. Evaluation of regression procedures for methods comparison studies. Clinical Chemistry. 1993;39(3):424-432.
Deming WE. Statistical Adjustment of Data. Wiley; 1943.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.