Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions R/metrics.R
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ objective_function <- function(layout_df,
#' @inheritParams objective_function
#' @inheritDotParams objective_function
#' @param factorial_separator A character used to separate treatments in the factorial design (default: "-")
#' @param interaction_weight Weight for the balance of interactions (default: 1)
#' @param main_weight Weight for the score of main treatments (default: 1)
#'
#' @examples
#' treatment_a <- paste0("A", 1:8)
Expand All @@ -88,6 +90,8 @@ objective_function <- function(layout_df,
objective_function_factorial <- function(layout_df,
swap,
spatial_cols,
interaction_weight = 1,
main_weight = 1,
factorial_separator = "-",
...) {
if (is.null(factorial_separator) || factorial_separator == "") {
Expand All @@ -109,16 +113,24 @@ objective_function_factorial <- function(layout_df,
)

# create temp columns
# now <- as.numeric(Sys.time())
treatment_n <- paste0("treatment_", 1:n_treatments)
layout_df[treatment_n] <- subtreatments

treatment_score <- calculate_balance_score(layout_df, swap, spatial_cols)
subtreatment_scores <- vapply(treatment_n, function(treatment) {
objective_function(layout_df, treatment, spatial_cols, ...)$score
}, numeric(1))
if (interaction_weight > 0) {
treatment_score <- calculate_balance_score(layout_df, swap, spatial_cols)
} else {
treatment_score <- 0
}

if (main_weight > 0) {
subtreatment_scores <- vapply(treatment_n, function(treatment) {
objective_function(layout_df, treatment, spatial_cols, ...)$score
}, numeric(1))
} else {
subtreatment_scores <- 0
}

return(list(score = sum(subtreatment_scores) + treatment_score))
return(list(score = main_weight * sum(subtreatment_scores) + interaction_weight * treatment_score))
}

#' Calculate Balance Score for Experimental Design
Expand Down
6 changes: 6 additions & 0 deletions man/objective_function_factorial.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 27 additions & 7 deletions vignettes/factorial.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ vignette: >

## Overview

Factorial designs are experimental designs used to study the effects of two or more factors simultaneously. They allow estimation of main effects and interactions between factors, making them efficient and informative.
Factorial designs are experimental designs used to study the effects of two or more factors simultaneously. They
allow estimation of main effects and interactions between factors, making them efficient and informative.

```{r load-package}
library(speed)
Expand All @@ -34,7 +35,8 @@ library(patchwork)

## Setting Up Factorial Design with speed

Now we can create a data frame representing a factorial design. Note that the treatment column we are creating is the interaction (or combination) of the individual treatments.
Now we can create a data frame representing a factorial design. Note that the treatment column we are creating
is the interaction (or combination) of the individual treatments.

```{r factorial-df}
treatment_a <- paste0("A", 1:8)
Expand Down Expand Up @@ -63,20 +65,33 @@ p + pa + pb + plot_layout(ncol = 3)

### Performing the Optimisation

For factorial designs, speed provides a customised objective function `objective_function_factorial`. The `optimise_params` argument is also used in this case to adjust the optimisation strategy due to the difficulty of optimising such designs.
For factorial designs, speed provides a customised objective function `objective_function_factorial` which
allows us to pass `interaction_weight` and `main_weight` arguments to control the spatial balance of those
effects. The `optimise_params` argument is also used in this case to adjust the optimisation strategy due to the
difficulty of optimising such designs.

Make sure `factorial_separator` matches how you constructed the interaction treatment (here we used `"-"`). If your treatments use a different separator (e.g. `"A1:B2"`), pass `factorial_separator = ":"`.
Make sure `factorial_separator` matches how you constructed the interaction treatment (here we used `"-"`). If
your treatments use a different separator (e.g. `"A1:B2"`), pass `factorial_separator = ":"`.

```{r factorial-example}
optimise_params <- optim_params(
swap_count = 3,
random_initialisation = 10,
adaptive_swaps = TRUE,
swap_all_blocks = TRUE,
cooling_rate = 0.999
)

factorial_result <- speed(
data = factorial_design,
swap = "treatment",
swap_within = "block",
spatial_factors = ~ row + col,
obj_function = objective_function_factorial,
optimise_params = optim_params(random_initialisation = 50, adaptive_swaps = TRUE),
optimise_params = optimise_params,
early_stop_iterations = 10000,
iterations = 200000,
interaction_weight = 10,
seed = 112
)

Expand All @@ -85,9 +100,14 @@ factorial_result

### Output of the Optimisation

The output summarises the optimisation of the factorial **interaction** treatment (e.g. `"A1-B2"`) across the spatial layout. The reported score is for the whole design after optimisation, and the returned `design_df` contains the updated treatment allocation.
The output summarises the optimisation of the factorial **interaction** treatment (e.g. `"A1-B2"`) across the
spatial layout. The reported score is for the whole design after optimisation, and the returned `design_df`
contains the updated treatment allocation.

Because the treatment column encodes multiple factors, it can be helpful to split it back into its component factors (e.g. `treatment_a` and `treatment_b`) when inspecting the result. This lets you check whether the optimisation improved not only the interaction layout, but also the balance/adjacency patterns of the main effects.
Because the treatment column encodes multiple factors, it can be helpful to split it back into its component
factors (e.g. `treatment_a` and `treatment_b`) when inspecting the result. This lets you check whether the
optimisation improved not only the interaction layout, but also the balance/adjacency patterns of the main
effects.

```{r factorial-output}
str(factorial_result)
Expand Down
Loading