*! version 0.2 3mar2015
help randomize

Title

randomize -- Random assignment for experimental trials, including blocking, balance checking, and automated rerandomization.

Syntax

randomize [if] [in],
[options]

Main
balance:(varlist) List of variables on which to test for balance.

groups:(#) Number of groups to create of equal size within the assignment variable; default is 2.

generate(newvar) Name of the assignment variable; default is _assignment.

block(varlist) List of variables to block on. These are combined into a strata variable, and randomizations are conducted within blocks.

minruns(#) Minimum number of randomizations to run; default is 1. Per-block.

maxruns(#) Maximum number of randomizations to run; default is 1. Per-block.

seed(integer) The random number generator seed to use, which ensures the randomization is replicable. Can also be set manually.

replace Overwrite existing assignment variable.

aggregate(numlist) Provide a list of numbers denoting how the resulting assignments should be aggregated into larger groups.
This allows for unequal allocation sizes while still checking balance on equally sized groups. The list of numbers must sum to the number of groups.

Advanced
jointp(real) Minimum balance p-value allowable to accept a given randomization, ranging from 0 to 1.

details Show the detailed results for each randomization attempt, which are hidden by default.

Description

randomize conducts random assignment of units to equally sized groups. It can check for balance on a specified list of covariates.
If blocking variables are specified it will conduct the randomization within blocks. It can rerandomize within blocks a certain number of times, such as conducting 100 randomizations
and choosing the randomization with the best balance across covariates. It can also rerandomize until the balance statistic (Wilks' lambda on a manova)
exceeds a certain cut-off value (e.g. 0.2). If unequal allocation sizes are desired, multiple groups can be aggregated after the randomization.
Assignments are allocated in a random order within each block, ensuring that group sizes differ by no more than one observation in each block.

For clustered random assignment, one will need to handle the clustering manually, such as collapsing the dataset to the cluster level or choosing one representative unit
per cluster. The randomization algorithm can then be run on that dataset, and the assignments can be copied to all units in the cluster.

Examples

1. Randomize a dataset into 2 groups, checking for balance by gender.

. randomize, balance(gender)

2. Randomize a dataset into 5 equally-sized groups, blocking by state and gender.

. randomize, groups(3) balance(age gender) jointp(0.2)

3. Randomize a dataset into 3 groups, checking for balance on age and gender. Rerandomize up to 100 times or until the balance p-value exceeds 0.2.

. randomize, groups(3) balance(age gender) jointp(0.2) maxruns(100)

4. Create 4 groups, check for covariate balance on gender, race, and age, block on state, choose the most balanced of 500 randomizations within each block, and specify the random number generator seed.

. randomize, groups(4) balance(gender race age) block(state) minruns(500) seed(1)

5. Create a 10% / 20% / 70% split by randomizing into 10 equally sized groups then aggregating those assignments.

. randomize, groups(10) aggregate(1 2 7)

6. Use the quiet prefix to hide all randomization output and just get the result.

. quiet randomize, balance(state) minruns(1000)

7. Use the details option to show all randomization output.

. randomize, balance(state) minruns(1000) details

8. Simulated dataset example - randomize 10,000 records across 4 blocks, and take the best randomization out of 500 per block.

clear

set obs 10000

set seed 2

gen covariate = uniform()

gen block_var = ceil(uniform() * 4)

randomize, block(block_var) balance(covariate) minruns(500)

9. Clustered Randomization v1 - select a random record within the cluster, conduct the randomization on those records, then apply the assignment to the full cluster.

* Create a combined cluster id

egen cluster_id = group(cluster_field1 cluster_field2)

set seed 1

set sortseed 2

gen double random = runiform()

* Randomly order individuals within clusters.

bysort cluster_id (random): egen cluster_seq = seq()

* Randomize using the demographics of the first cluster member to check for balance.

randomize if cluster_seq == 1, balance(covar1 covar2) block(blockvar1 blockvar2) replace

* Expand assignment to all units in the cluster.

bysort cluster_id: egen assignment = mode(_assignment)

10. Clustered Randomization v2 - compress the dataset to the cluster level, conduct the randomization, then merge the assignment back to the full dataset.

* Create a combined cluster id

egen cluster_id = group(cluster_field1 cluster_field2)

set seed 1

set sortseed 2

* Save the uncompressed version of the dataset.

preserve

* Aggregate to the cluster level, creating summary statistics for the randomization.

collapse (mean) covar1 covar2 (max) rare_covar3 (count) cluster_size, by(cluster_id)

* Execute the randomization at the cluster level.

randomize, balance(covar1 covar2 rare_covar3) replace

* Restrict to the data that we need.

keep cluster_id _assignment

save "cluster-assignments.dta", replace

* Switch back to the full dataset.

restore

merge m:1 cluster_id using "cluster-assignments.data"

References

Lock Morgan, K. and Rubin, D. B. (2012). Rerandomization to improve covariate balance in experiments. Ann. Statist. Volume 40, Number 2, 1263-1282.

Lock Morgan, K. (2011). Rerandomization to improve covariate balance in randomized experiments. PhD dissertation. Harvard University, Department of Statistics.

Website

Randomize is maintained at http://github.com/ck37/randomize_ado

Authors

Chris J. Kennedy

University of California, Berkeley

ck37@berkeley.edu

http://ck37.com

Christopher B. Mann

Skidmore College

christopherbmann@gmail.com

http://www.christopherbmann.com

Acknowledgements

We thank Debby Kermer for earlier contributions to parts of the algorithm, John Ternovski for helpful comments, and Kari Lock Morgan for the underlying theory and suggestion of the Wilks lambda balance statistic.