I am trying to fit a model into an lrm
framework so I can bootstrap it with validate
. The model has already been developed elsewhere. However, when I use an offset term to account for coefficients already known, I get an error:
Error in lrm(Death ~ offset(2 * Age), data = patient_data) :
object 'sformula' not found
Do offsets not work in rms::lrm
even though the help file explicitly says they do?
library(rms)
patient_data <- data.frame(
PatientID = 1:1000,
Death = sample(c(0, 1), size = 1000, replace = TRUE),
Age = round(runif(1000, min = 20, max = 90), 1)
)
lrm(Death~Age, data = patient_data) #works fine
glm(Death ~ Age), family = "binomial", data = patient_data) #works fine
glm(Death ~ offset(2*Age), family = "binomial", data = patient_data) #works fine
lrm(Death ~ offset(2*Age),data = patient_data) #ERROR
While there is no solution for the bug in the code, there is a workaround (someone double check the code?)
# Define the function which will be applied to each bootstraped sample.
# Note, boot() will output the original data and a list of indices to construct
# bootstrapped sample
fBootMetrics <- function(tblOrgData, intIndex) {
# Create a bootstrap sample using the provided indices
tblBootData <- tblOrgData[intIndex, ]
# Fit the logistic regression model on the bootstrap sample
# The model uses coefficients from the above LASSO penalised model
mdlDeathBoot <- glm(
Death ~ 0 + offset(2 * Age),
family = "binomial",
data = tblBootData
)
# Obtain predicted probabilities on the bootstrap sample (apparent) and test
pred_boot <- predict(mdlDeathBoot, type = "response", newdata = tblBootData)
pred_org <- predict(mdlDeathBoot, type = "response", newdata = tblOrgData)
# Convert Death to numeric and subtract 1 as the factor levels are "1" and "2"
y_boot <- as.numeric(tblBootData$Death) - 1
y_org <- as.numeric(tblOrgData$Death) - 1
return(rms::val.prob(pred_boot, y_boot, pl = FALSE)[c("Dxy", "Intercept", "Slope")] - rms::val.prob(pred_org, y_org, pl = FALSE)[c("Dxy", "Intercept", "Slope")])
}
boot(data = patient_data,
statistic = fBootMetrics,
R = 50)$t -> tblMdlPerformance
colnames(tblMdlPerformance) <- c("Dxy", "Intercept", "Slope")
As for OP's actual question Do offsets not work in rms::lrm
, it seems like the comment by the rms
author here is still true:
looks like a bug.
lrm
only seems to supportoffset
if there are other covariates in the model and you are not suppressing the intercept.
We may check this by creating a toy covariate and add it to your lrm
formula:
patient_data$x = runif(1000)
lrm(Death ~ x + offset(2*Age), data = patient_data)
Indeed, this works.
A potential solution is given here: Error using offset argument in an intercept only model in lrm function R, from rms package; try lrm.fit
:
with(patient_data, lrm.fit(y = Death, offset = 2*Age))