Randomisation is one of the key aspects of clinical trials, ensuringthat treatment groups are balanced and that the results are not biased.Therandotools package provides functions to createrandomisation lists in R, with a focus on flexibility and ease ofuse.
Randomisation lists are easily created with therandolist function. Specify the number of participants torandomise (per strata, if there are any), any strata, the arms torandomise between, and the block sizes.
randolist(n =20,arms =c("Trt1","Trt2"))#> seq_in_strata block_in_strata blocksize seq_in_block arm#> 1 1 1 6 1 Trt1#> 2 2 1 6 2 Trt2#> 3 3 1 6 3 Trt1#> 4 4 1 6 4 Trt1#> 5 5 1 6 5 Trt2#> 6 6 1 6 6 Trt2#> 7 7 2 4 1 Trt2#> 8 8 2 4 2 Trt1#> 9 9 2 4 3 Trt2#> 10 10 2 4 4 Trt1#> 11 11 3 4 1 Trt1#> 12 12 3 4 2 Trt2#> 13 13 3 4 3 Trt2#> 14 14 3 4 4 Trt1#> 15 15 4 4 1 Trt1#> 16 16 4 4 2 Trt1#> 17 17 4 4 3 Trt2#> 18 18 4 4 4 Trt2#> 19 19 5 4 1 Trt2#> 20 20 5 4 2 Trt1#> 21 21 5 4 3 Trt1#> 22 22 5 4 4 Trt2In the above call,
n specifies the number of participants to randomise perstratum. In this case, we are randomising 20 participants in a singlestratum.arms specifies the names of the arms to randomisebetween.Any number of arms can be specified, sorandolist can beused for trials with two, three, even 10 or more arms, so platformtrials can be accommodated byrandolist, althoughimplementing them within the database is not trivial.
By default,randolist uses block randomisation - ratherthan using random selection along the whole list in the hope that thearms are balanced, it creates blocks of randomisation, whereby eachblock is balanced, and block sizes are chosen at random. This not onlyhelps with balancing, but also makes it harder to guess the nextallocation. Block sizes are controlled via theblocksizesargument, where the values should be the potential number of each arm toinclude in any given block. E.g.c(1,2) would produceblocks with either one of each arm, or two of each arm, for a totalblock size or 2 or 4.
Additionally,blocksizes are selected approximatelyproportional to Pascal’s Triangle, so that medium sizes blocks are morelikely to be selected than small or large blocks. This is done to ensurethat the randomisation list is not too predictable, and helps withbalance by reducing the chance of finishing mid-way through a largeblock.
To disable block randomisation, set the block size tondivided by the number of arms (in this casen/2, so10):
randolist(n =20,arms =c("Trt1","Trt2"),blocksizes =10)#> seq_in_strata block_in_strata blocksize seq_in_block arm#> 1 1 1 20 1 Trt2#> 2 2 1 20 2 Trt1#> 3 3 1 20 3 Trt2#> 4 4 1 20 4 Trt1#> 5 5 1 20 5 Trt2#> 6 6 1 20 6 Trt2#> 7 7 1 20 7 Trt1#> 8 8 1 20 8 Trt2#> 9 9 1 20 9 Trt2#> 10 10 1 20 10 Trt1#> 11 11 1 20 11 Trt2#> 12 12 1 20 12 Trt1#> 13 13 1 20 13 Trt1#> 14 14 1 20 14 Trt2#> 15 15 1 20 15 Trt1#> 16 16 1 20 16 Trt1#> 17 17 1 20 17 Trt1#> 18 18 1 20 18 Trt1#> 19 19 1 20 19 Trt2#> 20 20 1 20 20 Trt2Theblockrand function can also be used fornon-stratified randomisation lists.
It is very common to need a stratified randomisation where therandomisation is balanced within strata. This is done by specifying thestrata argument, which should be a list of the stratifyingvariables. The function will then create a randomisation list for eachstratum, and combine them into a single list. The list for each stratacontainsn participants.
rs<-randolist(n =10,strata =list(sex =c("Male","Female"),age =c("Teen","Adult")))table(rs$sex)#>#> Male Female#> 20 24table(rs$sex, rs$arm)#>#> A B#> Male 10 10#> Female 12 12By using factors to specify the strata, the labels and levels areavailable for use when exporting the randomisation list, which is usefulfor importing into electronic data capture systems such as REDCap, whichrequires a specific format.
It is not uncommon to have unbalanced randomisation lists. E.g. 2control participants per experimental participant. This is easily doneby changing thearms argument:
Adaptive trials sometimes modify the randomisation balance part waythrough a trial, which can be accomplished via this method.
It can be helpful to summarize the randomisation list to check thatthe requirements, such as the balance, coding, etc, are met. Therandolist package includes asummary preciselyfor this purpose:
randolist(n =20,arms =c("Trt1","Trt2"))|>summary()#> ---- Randomisation list report ----#> -- Overall#> Total number of randomisations: 22#> Randomisation groups: Trt1 : Trt2#> Randomisation ratio: 1:1#> Randomisations to each arm:#> Trt1 Trt2#> 11 11#> Block sizes:#> 4 6#> 4 1The summary for stratified randomisation lists also includesinformation at the strata level.
Once a randomisation list is created, it needs to be transferred intoa system that will ultimately perform the randomisation. We primarilyuse two systems for this: REDCap and SecuTrial, but you might useothers, which may require other modifications. Therandolist package includes a function to convert therandomisation list into a format that should be, with minimal effort, beimportable into these systems.
# create a very small randomisation list for demonstration purposesrs2<-randolist(n =2,blocksizes =1,arms =c("Aspirin","Placebo"),strata =list(sex =c("Male","Female"),age =c("Teen","Adult")))Therandolist_to_db function is used to convert therandomisation list into a format that can be imported into the system.The function takes the randomisation list as input, and converts it to adata frame with the columns appropriate for the target database(target_db). In the case of REDCap, it is necessary toprovide a data frame which maps the arms provided inrandolist to the database variables.
randolist_to_db(rs2,target_db ="REDCap",rando_enc =data.frame(arm =c("Aspirin","Placebo"),rand_result =c(1,2)),strata_enc =list(sex =data.frame(sex =c("Male","Female"),code =1:2),age =data.frame(age =c("Teen","Adult"),code =1:2)))#> rand_result sex age#> 1 1 1 1#> 2 2 1 1#> 3 1 2 1#> 4 2 2 1#> 5 2 1 2#> 6 1 1 2#> 7 1 2 2#> 8 2 2 2SecuTrial uses a more standardised format, sorando_encoding is not required.
randolist_to_db(rs2,target_db ="secuTrial",strata_enc =list(sex =data.frame(sex =c("Male","Female"),code =1:2),age =data.frame(age =c("Teen","Adult"),code =1:2)))#> Number Group sex age#> 1 1 Aspirin value = 1 value = 1#> 2 2 Placebo value = 1 value = 1#> 3 3 Aspirin value = 2 value = 1#> 4 4 Placebo value = 2 value = 1#> 5 5 Placebo value = 1 value = 2#> 6 6 Aspirin value = 1 value = 2#> 7 7 Aspirin value = 2 value = 2#> 8 8 Placebo value = 2 value = 2The dataframe returned can then be exported to CSV or xlsx andimported into the relevant database.