Skip to contents

Introduction

Use ec50_multimodel() when you want to fit more than one candidate drc model to the same isolates and strata. This is useful during model selection, when you need EC estimates and model-selection statistics in the same output.

Data

The examples use a small subset of multi_isolate so the vignette runs quickly while still showing the grouped workflow.

data(multi_isolate)

example_data <- subset(
  multi_isolate,
  isolate %in% 1:5 & fungicida == "Fungicide A"
)

head(example_data)
##   isolate   field   fungicida  dose     growth
## 1       1 Organic Fungicide A 0e+00 20.2082399
## 2       1 Organic Fungicide A 1e-05 20.1168279
## 3       1 Organic Fungicide A 1e-04 19.2479678
## 4       1 Organic Fungicide A 1e-03 15.8123455
## 5       1 Organic Fungicide A 1e-02  7.3206757
## 6       1 Organic Fungicide A 1e-01  0.6985264

Inspect the raw dose-response observations before comparing models. Because each isolate can have repeated observations at the same dose, this plot uses jittered points instead of connecting observations with lines.

ggplot(example_data, aes(dose, growth, color = factor(isolate))) +
  geom_jitter(width = 0.08, height = 0, alpha = 0.85, size = 2) +
  facet_wrap(~field) +
  scale_x_log10() +
  labs(x = "Dose", y = "Growth", color = "Isolate") +
  theme_light()
## Warning in scale_x_log10(): log-10 transformation introduced
## infinite values.

Jittered dose-response scatter plot for five isolates exposed to Fungicide A, faceted by field system.

Compare Models

Pass a list of candidate model functions to fct. The function fits each model for each isolate and stratum, then appends model-selection statistics returned by drc::mselect().

df_models <- ec50_multimodel(
  growth ~ dose,
  data = example_data,
  isolate_col = "isolate",
  strata_col = "field",
  fct = list(drc::LL.3(), drc::LL.4(), drc::W2.3()),
  interval = "delta"
)

head(df_models)
##     ID        field    Estimate   Std..Error       Lower       Upper    logLik
## 1    1      Organic 0.006072082 0.0005740341 0.004902813 0.007241351 -45.15079
## 36   2 Conventional 0.101455765 0.0076364691 0.085900787 0.117010744 -43.53183
## 71   3      Organic 0.003776957 0.0002432571 0.003281459 0.004272456 -36.09845
## 106  4 Conventional 0.079971237 0.0055655891 0.068634503 0.091307971 -38.42154
## 141  5      Organic 0.006122508 0.0004575060 0.005190599 0.007054418 -41.41058
## 11   1      Organic 0.006364103 0.0007031475 0.004930024 0.007798182 -44.69257
##           IC Lack.of.fit   Res.var model
## 1   98.30158   0.7271292 0.8451681  LL.3
## 36  95.06365   0.9866424 0.7704874  LL.3
## 71  80.19689   0.3897432 0.5038400  LL.3
## 106 84.84309   0.8328859 0.5753664  LL.3
## 141 90.82115   0.9744433 0.6825317  LL.3
## 11  99.38515   0.7370811 0.8498845  LL.4

The model column identifies the candidate model. The IC column is the information criterion reported by drc::mselect() for the fitted model.

Pick Candidate Models

You can rank candidate models within each isolate and stratum using base R. Lower IC values indicate stronger relative support among the compared models.

ranked_models <- df_models[order(df_models$field, df_models$ID, df_models$IC), ]
best_models <- ranked_models[!duplicated(ranked_models[c("field", "ID")]), ]

best_models[, c("ID", "field", "model", "Estimate", "Std..Error", "IC")]
##     ID        field model    Estimate   Std..Error       IC
## 36   2 Conventional  LL.3 0.101455765 0.0076364691 95.06365
## 106  4 Conventional  LL.3 0.079971237 0.0055655891 84.84309
## 1    1      Organic  LL.3 0.006072082 0.0005740341 98.30158
## 712  3      Organic  W2.3 0.003233688 0.0001397399 76.96774
## 141  5      Organic  LL.3 0.006122508 0.0004575060 90.82115

Visualize Model Comparison

Plot the information criterion across isolates to see whether one model is consistently preferred.

plot_models <- df_models
plot_models$ID <- as.numeric(plot_models$ID)

ggplot(plot_models, aes(ID, IC, color = model)) +
  geom_point(position = position_dodge(width = 0.35), size = 2) +
  facet_wrap(~field) +
  scale_x_continuous(breaks = sort(unique(plot_models$ID))) +
  labs(x = "Isolate", y = "Information criterion") +
  theme_light()

Point plot of information criterion values by isolate for each candidate model and field system.

After choosing an appropriate model, use estimate_EC50() for the final estimation workflow if a single model should be applied across the full dataset.