Merged block randomization is a restricted randomization method designed for small clinical trials (at most 100 subjects) or trials with small strata, for example in multicentre trials. It can be used for more than two groups (treatment arms) or unequal randomization ratios.
There are two functions in the mergedblocks package:
mergedblocks()
, to create randomization lists for a
single stratum.mergedblocksmulti()
, to create randomization lists for
multiple strata.The package can be installed by typing
install.packages("mergedblocks")
in the R terminal. In
addition to the package, a Shiny app is available from https://svdpas.shinyapps.io/mergedblocks/, which can be
used to create randomization lists for two groups (treatment arms).
A detailed description of the method is available in Van der Pas (2019). Merged block randomisation: A novel randomisation procedure for small clinical trials. Clinical Trials 16(3):246-252.
In this vignette, we provide a guided tour of the two functions in the package, illustrating the options within each function. The sections are:
mergedblocks()
mergedblocksmulti()
mergedblocks()
For two treatment arms with 1:1 allocation,
mergedblocks()
only requires the number of individuals to
be randomized as input, via the argument n
. For example, we
obtain a randomization list for 50 individuals via:
mergedblocks(n = 50)
#> [1] "1" "2" "1" "2" "1" "2" "1" "2" "1" "2" "1" "2" "2" "1" "2" "2" "1" "1" "1"
#> [20] "2" "1" "2" "1" "2" "2" "1" "1" "2" "1" "2" "2" "2" "1" "1" "2" "1" "2" "1"
#> [39] "1" "2" "2" "1" "1" "1" "2" "1" "2" "2" "1" "2"
By default, the two groups will get numeric labels, in this case “1”
and “2”. You can select custom labels with the labels
argument. For example:
mergedblocks(n = 50, labels = c("treatment", "placebo"))
#> [1] "treatment" "placebo" "placebo" "treatment" "placebo" "treatment"
#> [7] "treatment" "placebo" "treatment" "placebo" "placebo" "placebo"
#> [13] "treatment" "treatment" "placebo" "treatment" "treatment" "placebo"
#> [19] "placebo" "treatment" "treatment" "placebo" "treatment" "treatment"
#> [25] "placebo" "treatment" "placebo" "placebo" "placebo" "treatment"
#> [31] "placebo" "placebo" "treatment" "treatment" "treatment" "placebo"
#> [37] "placebo" "placebo" "treatment" "treatment" "treatment" "treatment"
#> [43] "placebo" "placebo" "treatment" "treatment" "placebo" "placebo"
#> [49] "placebo" "treatment"
The argument ratio
can be used to select the desired
randomization ratio. For example, if we wish to randomize 50 individuals
to two groups in a 1:2 ratio, with allocations labelled as “A” and “B”,
we would use:
mergedblocks(n = 50, ratio = c(1, 2), labels = c("A", "B"))
#> [1] "A" "B" "B" "A" "B" "B" "B" "B" "A" "A" "B" "B" "A" "B" "B" "B" "A" "B" "B"
#> [20] "A" "B" "A" "B" "B" "B" "B" "A" "A" "B" "A" "B" "A" "B" "B" "B" "B" "B" "A"
#> [39] "B" "A" "B" "B" "A" "B" "B" "B" "A" "B" "B" "B"
Or for a 3:2 ratio:
The argument ratio
can be used to obtain randomization
lists for more than two treatment arms. Suppose the number of treatment
arms is N. Then the
ratio
argument is set to a vector of length N, with the entries of the vector
indicating the desired randomization ratio.
For example, to randomize 50 subjects to three treatment arms in a 1:1:1 ratio:
mergedblocks(n = 50, ratio = c(1, 1, 1))
#> [1] "1" "2" "1" "3" "1" "3" "2" "2" "1" "2" "3" "2" "3" "1" "1" "3" "3" "2" "1"
#> [20] "1" "3" "2" "1" "2" "3" "3" "1" "2" "3" "3" "1" "2" "2" "2" "1" "1" "2" "3"
#> [39] "2" "3" "1" "1" "3" "2" "2" "3" "1" "2" "3" "3"
If other labels than the default numeric ones are desired, the
argument labels
can be used. It requires a vector of the
same length as ratio
. For example, 1:1:1 allocation to
treatments “A”, “B” and “C”:
mergedblocks(n = 50, ratio = c(1, 1, 1), labels = c("A", "B", "C"))
#> [1] "A" "C" "B" "A" "A" "C" "B" "B" "C" "C" "B" "B" "A" "B" "A" "A" "C" "C" "B"
#> [20] "C" "A" "A" "C" "A" "C" "B" "B" "A" "A" "C" "B" "C" "B" "C" "A" "A" "B" "C"
#> [39] "B" "C" "A" "B" "C" "B" "B" "A" "B" "A" "A" "C"
For e.g. five treatment arms:
mergedblocks(n = 50, ratio = c(1, 1, 1, 1, 1), labels = c("A", "B", "C", "D", "E"))
#> [1] "C" "A" "E" "D" "C" "A" "B" "B" "E" "E" "A" "C" "B" "D" "D" "D" "D" "B" "C"
#> [20] "E" "E" "A" "E" "C" "B" "A" "B" "A" "D" "B" "C" "D" "C" "C" "E" "A" "C" "E"
#> [39] "D" "A" "B" "A" "A" "D" "B" "E" "D" "C" "E" "D"
Unequal allocation is also possible. For example, to randomize 50 individuals to three treatment arms, “A”, “B” and “C”, in a 1:1:2 ratio:
mergedblocks(n = 50, ratio = c(1, 1, 2), labels = c("A", "B", "C"))
#> [1] "C" "C" "C" "C" "B" "B" "A" "A" "B" "C" "C" "B" "C" "C" "A" "A" "B" "A" "C"
#> [20] "C" "C" "C" "C" "A" "C" "B" "B" "A" "A" "A" "B" "C" "C" "C" "C" "B" "B" "C"
#> [39] "B" "A" "C" "C" "C" "A" "A" "A" "C" "C" "B" "B"
The arguments of ratio
and labels
are
linked In the example above, treatment “C” was assigned twice as often
as “A” or “B”. With the following code, treatment “A” is assigned twice
as often as “B” or “C” (2:1:1 ratio).
mergedblocks(n = 50, ratio = c(2, 1, 1), labels = c("A", "B", "C"))
#> [1] "B" "A" "A" "B" "C" "A" "C" "A" "A" "C" "A" "B" "C" "A" "B" "A" "A" "A" "C"
#> [20] "B" "B" "C" "A" "B" "A" "A" "A" "C" "A" "A" "B" "B" "A" "C" "A" "B" "A" "A"
#> [39] "C" "C" "C" "C" "B" "A" "A" "A" "A" "B" "A" "A"
As a final example, to randomize 100 individuals to four treatment arms in a 2:2:3:3 ratio:
four.arms <- mergedblocks(n = 100, ratio = c(2, 2, 3, 3), labels = c("A", "B", "C", "D"))
four.arms
#> [1] "C" "B" "B" "C" "D" "C" "C" "A" "A" "C" "D" "A" "A" "D" "D" "B" "B" "D"
#> [19] "C" "C" "A" "A" "D" "D" "D" "C" "C" "B" "D" "C" "B" "B" "D" "D" "D" "D"
#> [37] "B" "C" "A" "B" "C" "C" "C" "D" "A" "A" "C" "C" "D" "B" "C" "C" "A" "A"
#> [55] "D" "D" "B" "D" "D" "B" "D" "B" "A" "C" "D" "B" "C" "C" "A" "A" "D" "D"
#> [73] "C" "C" "B" "B" "B" "D" "D" "D" "A" "C" "C" "A" "A" "B" "C" "D" "C" "A"
#> [91] "C" "C" "C" "A" "C" "A" "D" "A" "C" "B"
table(four.arms)
#> four.arms
#> A B C D
#> 21 19 32 28
The randomization lists can be saved using
e.g. write.table()
or write.csv()
. For
example:
example.list <- mergedblocks(n = 50, ratio = c(1, 2), labels = c("A", "B"))
write.csv2(example.list, file = "./YourFilePath/ExampleList.csv")
This particular example will yield a CSV file with two columns. The first column contains the numbers 1-50, the second column contains the allocations.
mergedblocksmulti()
The function mergedblocksmulti()
can be used to create
randomization lists for multiple strata, as in a multicentre trial. The
function allows for different sample sizes per stratum, and for unequal
randomization ratios.
The function mergedblocksmulti()
has four arguments. The
arguments ratio
and labels
work the same as
for the single stratum function mergedblocks()
. The focus
of this part of the vignette will be on K
and
n
, the two arguments that work differently compared to the
arguments of mergedblocks()
.
The argument K
is set to the number of strata. If the
number of individuals per stratum is the same for each stratum, the
argument n
can be set to this number.
For example, to create randomization lists for three strata with 25 individuals per stratum:
mergedblocksmulti(K = 3, n = 25)
#> V1 V2 V3
#> 1 2 1 1
#> 2 2 2 1
#> 3 1 2 2
#> 4 1 1 2
#> 5 1 1 1
#> 6 2 2 2
#> 7 2 2 2
#> 8 1 2 1
#> 9 1 1 2
#> 10 2 1 1
#> 11 1 2 2
#> 12 2 1 1
#> 13 1 1 1
#> 14 1 2 2
#> 15 2 2 2
#> 16 2 1 1
#> 17 2 2 2
#> 18 1 2 2
#> 19 2 1 1
#> 20 1 1 1
#> 21 2 1 1
#> 22 1 1 2
#> 23 1 2 2
#> 24 2 2 1
#> 25 2 1 2
In the code above, default 1:1 allocation was used, with default
numeric treatment labels. The output is a dataframe with one column for
each stratum. As for mergedblocks()
, the allocation ratio
can be changed to e.g. 1:2 allocation, and custom labels can be used,
e.g. “treatment” and “placebo”:
mergedblocksmulti(K = 3, n = 25, ratio = c(1, 2), labels = c("treatment", "placebo"))
#> V1 V2 V3
#> 1 placebo placebo placebo
#> 2 placebo placebo treatment
#> 3 placebo treatment placebo
#> 4 treatment placebo treatment
#> 5 treatment placebo placebo
#> 6 placebo treatment treatment
#> 7 placebo placebo placebo
#> 8 treatment placebo placebo
#> 9 treatment treatment treatment
#> 10 placebo placebo placebo
#> 11 placebo treatment placebo
#> 12 placebo placebo placebo
#> 13 placebo treatment placebo
#> 14 treatment placebo placebo
#> 15 placebo placebo treatment
#> 16 treatment treatment placebo
#> 17 placebo placebo placebo
#> 18 treatment placebo placebo
#> 19 placebo treatment treatment
#> 20 placebo placebo treatment
#> 21 placebo treatment placebo
#> 22 placebo placebo placebo
#> 23 placebo placebo treatment
#> 24 placebo placebo placebo
#> 25 treatment placebo placebo
As a further example, the following code yields randomization lists for four strata, 30 individuals per stratum, with 1:1:1 allocation of three treatments labelled “A”, “B” and “C”.
mergedblocksmulti(K = 4, n = 30, ratio = c(1, 1, 1), labels = c("A", "B", "C"))
#> V1 V2 V3 V4
#> 1 C C C C
#> 2 A C B B
#> 3 C A A C
#> 4 B B B A
#> 5 B A A A
#> 6 A C C B
#> 7 A B B B
#> 8 C B C C
#> 9 B A A A
#> 10 C C A A
#> 11 A B B A
#> 12 B B A C
#> 13 A A C B
#> 14 B A B C
#> 15 B A C A
#> 16 C C B B
#> 17 A C A B
#> 18 C A B A
#> 19 C B C B
#> 20 A B A C
#> 21 B C B C
#> 22 C C C C
#> 23 C B C A
#> 24 B A A A
#> 25 A C A B
#> 26 A B C C
#> 27 B A A A
#> 28 A A C B
#> 29 B B B B
#> 30 C B B C
The argument n
can be used to incorporate varying sample
sizes. For example, suppose we have three strata, with sample sizes 20,
30 and 25 In each stratum, 1:1 allocation to treatments “A” and “B” is
desired. We could use the following code:
mergedblocksmulti(K = 3, n = c(20, 30, 25), ratio = c(1, 1), labels = c("A", "B"))
#> V1 V2 V3
#> 1 A B B
#> 2 B A A
#> 3 B A A
#> 4 A A B
#> 5 B B B
#> 6 A A A
#> 7 A B B
#> 8 A B B
#> 9 B B A
#> 10 B A A
#> 11 B B B
#> 12 B A A
#> 13 A B B
#> 14 A A A
#> 15 A B B
#> 16 B A A
#> 17 B B A
#> 18 A A B
#> 19 A A B
#> 20 B B A
#> 21 <NA> A A
#> 22 <NA> B B
#> 23 <NA> A B
#> 24 <NA> B A
#> 25 <NA> B A
#> 26 <NA> A <NA>
#> 27 <NA> B <NA>
#> 28 <NA> A <NA>
#> 29 <NA> A <NA>
#> 30 <NA> B <NA>
The argument n
is now set to a vector with the desired
sample sizes. The output is a dataframe with three columns, one per
stratum. The columns with sample sizes 20 and 25 are padded with
NAs.
As a further example, with the following code we obtain randomization lists for five strata, sample sizes 35, 30, 40, 20 and 15, for 1:1:1 allocation to treatments “A”, “B” and “C”.
mergedblocksmulti(K = 5, n = c(35, 30, 40, 20, 15), ratio = c(1, 1, 1), labels = c("A", "B", "C"))
#> V1 V2 V3 V4 V5
#> 1 A C C C A
#> 2 B A B C B
#> 3 A B A A B
#> 4 C A C B C
#> 5 C B A B C
#> 6 B A B A A
#> 7 C C B B B
#> 8 A C A C A
#> 9 B C C B A
#> 10 C B B C C
#> 11 B A C A C
#> 12 A C A C B
#> 13 C B B A C
#> 14 C A A B B
#> 15 A B A A A
#> 16 B B C B <NA>
#> 17 C C C C <NA>
#> 18 A A C A <NA>
#> 19 B C A A <NA>
#> 20 A B B B <NA>
#> 21 C B B <NA> <NA>
#> 22 A C C <NA> <NA>
#> 23 B A B <NA> <NA>
#> 24 A C A <NA> <NA>
#> 25 B B A <NA> <NA>
#> 26 B A A <NA> <NA>
#> 27 C A B <NA> <NA>
#> 28 C A C <NA> <NA>
#> 29 C C B <NA> <NA>
#> 30 A B C <NA> <NA>
#> 31 B <NA> C <NA> <NA>
#> 32 C <NA> A <NA> <NA>
#> 33 A <NA> C <NA> <NA>
#> 34 B <NA> B <NA> <NA>
#> 35 A <NA> B <NA> <NA>
#> 36 <NA> <NA> A <NA> <NA>
#> 37 <NA> <NA> B <NA> <NA>
#> 38 <NA> <NA> A <NA> <NA>
#> 39 <NA> <NA> C <NA> <NA>
#> 40 <NA> <NA> C <NA> <NA>
The randomization lists can be saved using
e.g. write.table()
or write.csv()
. For
example:
example.list <- mergedblocksmulti(K = 5, n = c(35, 30, 40, 20, 15), ratio = c(1, 1, 1), labels = c("A", "B", "C"))
write.csv2(example.list, file = "./YourFilePath/ExampleList.csv")
This particular example will yield a CSV file with six columns. The first column contains the numbers 1-40, the remaining five columns contain the allocations per stratum (one column per stratum).