*! version 1.4 April 2017

Title

randtreat -- Random treatment assignment and dealing with misfits

Syntax

randtreat [if] [in] ,
generate(newvar)
[options]

Treatment variable
* generate(newvar) generate new treatment variable encoding treatment status

replace replace treatment variable if newvar exists

setseed(#) set random-number seed to replicate assignment; see set seed

Assignment parameters
strata(varlist) list of variables for stratified treatment assignment

multiple(integer) number of equal treatment groups; default is multiple(2)

unequal(fractions) fractions for unequal treatments (see below); default is unequal(1/2 1/2)

misfits(method) specify a method to deal with "misfits" (see below); method may be missing (default), strata, global, wstrata or wglobal

* generate(newvar) is required.

Description

The randtreat command performs random treatment assignment.
It's purpose is twofold: to easily randomize multiple, possibly unequal treatments across strata and to provide methods to deal with "misfits",
an issue first described by Bruhn and McKenzie (2011) and later generalized by Carril (2017).

The program presumes that the current dataset corresponds to units (e.g. individuals, firms, etc.) to be randomly allocated to treatment statuses.
When run, it creates a new variable encoding treatment status, which is randomly assigned.
The seed can be set with the setseed option, so the random assignment can be replicated.
The command defaults to two treatments, more equally proportioned treatments can be specified with the multiple(integer) option.
Alternatively, multiple treatments of unequal proportions can be specified with the unequal(fraction) option.
A stratified assignment can be performed using the strata(varlist) option.
If specified, the random assignment will be carried out for each stratum defined by the unique combinations of values of varlist.

Whenever the number of observations in a given stratum is not a multiple of the number of treatments or the least common multiple of the treatment fractions,
then that stratum is going to have misfits, that is,
observations that can't be neatly distributed among the treatments.
When run, randtreat reports the number of misfits produced by the combination of assignment parameters and the current dataset.
Misfits are automatically marked with missing values in the treatment variable, but additionally randtreat provides several methods to deal with them.
The method can be specified with the misfits() option (see below).

Options

Treatment variable

generate(newvar) creates a new variable encoding randomly assigned treatment status. Treatment values are consecutive nonnegative integers.

replace replaces the treatment newvar if it already exists.

setseed(#) specifies the initial value of the random-number seed used to assign treatments.
It can be set so that the random treatment assignment can be replicated.
See set seed for more information.

Assignment parameters

strata(varlist) is used to perform a stratified allocation on the variables in varlist.
If specified, the random assignment will be carried out in each stratum identified by the unique combination of the varlist variables' values.
Notice that this option is almost identical to using by (see [D] by), except that the command is not independently run for the specified variables, because global existence of misfits across strata must be accounted for.

multiple(integer) specifies the number of equally proportioned treatments to be assigned.
The default (and minimum) is multiple(2), unless the unequal() option is specified, in which case this option is redundant and should not be specified (see below).

unequal(fractions) is used to specify unequal treatment fractions.
Each fraction must be of the form a/b and must belong to (0,1).
Fractions must be separated by spaces and their sum must add up exactly to 1.

For example, unequal(1/2 1/4 1/4) will randomly assign half of the observations to the "control" group (assumed to correspond to the first fraction), and then divide evenly the rest of the observations into two treatments.
Notice that this option implicitly defines the number of treatments (e.g. 3), so when unequal() is used, mult() is redundant and should be avoided.

misfits(method) specifies which method to use in order to deal with misfits.
More details on the internal workings of these methods are available in
Carril (2017)
or in my related blog post.
The available methods are:

missing is the default option and simply leaves misfit observations as missing values in the treatment variable, so the user can later deal with misfits as he sees fit.

strata randomly allocates misfits independently across all strata, without weighting treatments as specified in unequal.
This method prioritizes balance of misfits' treatment allocation within each stratum (they can't differ by more than 1), but may harm original treatment fractions if the number of misfits is large.

global randomly allocates all misfits globally, without weighting treatments as specified in unequal.
This method prioritizes global balance of misfits' treatment allocation (they can't differ by more than 1), but may harm original treatment fractions if the number of misfits is large.

wstrata randomly allocates misfits independently across all strata, weighting treatments as specified in unequal.
This ensures that the fractions specified in unequal() affect the within-distribution of treatments among misfits, so overall balance of unequal treatments should be (almost) attained.
However, this method doesn't ensure the balance of misfits' treatment allocation within each stratum (they could differ by more than 1).

wglobal randomly allocates all misfits globally, weighting treatments as specified in unequal.
This ensures balance at the the global level and also respects unequal fractions of treatments, even when the number of misfits is large.
However, this method doesn't ensure the global balance of misfits' treatment allocation (they could differ by more than 1).
The downside is that this method could produce even greater unbalance at the finer level (in each stratum), specially if the number of misfits is relatively large.

Examples

I suggest you tabulate the generated treatment variable with the missing option after running each example.
First, load the fictional blood-pressure data:

sysuse bpwide, clear

Basic usage:

randtreat, generate(treatment)
randtreat, generate(treatment) replace mult(5)

Define stratification variables and unequal treatments, dealing with misfits:

randtreat, generate(treatment) replace unequal(1/2 1/3 1/6)
randtreat, generate(treatment) replace unequal(1/2 1/3 1/6) strata(sex agegrp) misfits(strata)
randtreat, generate(treatment) replace unequal(1/2 1/3 1/6) strata(sex agegrp) misfits(global)

Choose very unbalanced treatment fractions and dealing with misfits with and without weights:

randtreat, generate(treatment) replace unequal(2/5 1/5 1/5 1/5) misfits(global) setseed(12345)
randtreat, generate(treatment) replace unequal(2/5 1/5 1/5 1/5) misfits(wglobal) setseed(12345)

Notes

Beware of (ab)using unequal() with fractions that yield a large least common multiple (LCM), because that may produce a large number of misfits. For example, consider the following setup:

sysuse bpwide, clear
randtreat, generate(treatment) unequal(2/5 1/3 3/20 3/20)
tab treatment, missing

Since the LCM of the specified fractions is 60, the theoretical maximum number of misfits per stratum could be 59.
In this particular dataset, this configuration produces 58 misfits, which is a relatively large number given that the dataset has 120 observations.

Author

Alvaro Carril

Research Analyst at J-PAL LAC

acarril@fen.uchile.cl

Acknowledgments

I'm indebted to several "random helpers" at the Random Help Google user group and in the Statalist Forum, who provided coding advice and snippets.
Colleagues at the J-PAL LAC office, specially Olivia Bordeu and Diego Escobar, put up with my incoherent ideas and helped me steer this into something mildly useful.

References

Bruhn, Miriam, and David McKenzie. 2011. Tools of the Trade: Doing Stratified Randomization with Uneven Numbers in Some Strata. Blog. The World Bank: Impact Evaluations.
http://blogs.worldbank.org/impactevaluations/tools-of-the-trade-doing-stratified-randomization-with-unequal-numbers-in-some-strata.

Carril, Alvaro. 2017. Dealing with misfits in random treatment assignment. Stata Journal (forthcoming). DOI: 10.13140/RG.2.1.2859.8807
https://www.researchgate.net/publication/292091060_Dealing_with_misfits_in_random_treatment_assignment.