Block randomisation with different predefined block sizes



I would like to randomize 189 participants to one of three treatment conditions. I would like to do so using a block randomisation method with 3 blocks, two of size 45 and one of size 54. How can I do this using R?


You may want to take a look at the blockrand package. The function blockrand() (inside of the package) takes several arguments, including block.sizes, which is a vector of integers specifying the sizes of blocks to use (in your case 45, 45, and 54). The documentation (see link above) will give you further detail.

Hope that helps.


True, I have looked at it but this function can also give me 3 blocks of 54 and one of 45, which is actually not what I want.


Even if you specify block.sizes = c(45, 45, 54)?

This thread might be relevant as well:


Shouldn't the sum of the block sizes equal the number of participants?


Okay, admitted... I like puzzles... Is this what you are looking for? :slightly_smiling_face:

# Load libraries

# Set seed for reproducible example

# Define function for creating the Randomized Block Design
rand_block_design = function(block_sizes, n_treatments){

  # Check arguments
  if(!all(block_sizes %% n_treatments == 0)){
    stop("All blocks_sizes MUST be divisible with n_treatments")
  # Sub function for generation repeats of block_1, block_..., block_n
  # Each repeated according to corresponding block size
  get_blocks = function(block_sizes){
    blocks = paste0("block_", rep(seq(1, length(block_sizes)), block_sizes))
  # Sub function for assuring balanced randomized treatment assignments
  # Creates a vector of shuffled, but balanced treatment_1, treatment_..., treatment_n
  # according to each of the block sizes
  get_treatments = function(block_sizes, n_treatments){
    list_of_treatments = sapply(block_sizes, function(x){
      list_of_groups = sapply(seq(1, n_treatments), function(i){
        return(rep(LETTERS[i], x/n_treatments))
  # Create data frame of Randomized Block Design
  rbd = data.frame(
    id = seq(1, sum(block_sizes)),
    block = get_blocks(block_sizes),
    treatment = get_treatments(block_sizes, n_treatments)
  # Done, return!

d = rand_block_design(block_sizes = c(45, 45, 54), n_treatments = 3) %>% as_tibble
d %>% count(block)
# # A tibble: 3 x 2
#   block       n
#   <fct>   <int>
# 1 block_1    45
# 2 block_2    45
# 3 block_3    54
d %>% count(block, treatment)
# # A tibble: 9 x 3
#   block   treatment     n
#   <fct>   <fct>     <int>
# 1 block_1 A            15
# 2 block_1 B            15
# 3 block_1 C            15
# 4 block_2 A            15
# 5 block_2 B            15
# 6 block_2 C            15
# 7 block_3 A            18
# 8 block_3 B            18
# 9 block_3 C            18
d %>% pull(treatment)
#   [1] A C C C A C B A B C B C C B C A B B A B A C A B C C B C C A B A A C B B A B B A B A C A A A B
#  [48] B B A B B A A A C A A C A B A C C C A C B C B B A C C C C B C C A B B C A C B A B B A B B C B
#  [95] C B C C A C C A A A B C B A C B A B A C A C B A B C A B C A C A B A A A A A C B C B B B A B C
# [142] B C C
# Levels: A B C


Sorry you are right, it should be three blocks of 45 participants and one of 54. So block sizes should be (45, 45, 45, 54).


Then try to run my code above like so:

d = rand_block_design(block_sizes = c(45, 45, 45, 54), n_treatments = 3) %>% as_tibble

and see if you get the expected output? :slightly_smiling_face:


It works perfectly, thank you so much!


You're welcome! Please mark the answer, which holds the solution :slightly_smiling_face:


So, for clarity, @sasazxx, the block_sizes = argument works as expected when you explicitly specify them in a vector.


...and as always, please run some tests, to see if the function I wrote does indeed yield the expected output - No guarantees given. Also, remember to use the set.seed(), so you can reproduce your randomisation :slightly_smiling_face: