We now turn our focus from randomly sampling a subset of observations from a data set to that of generating a random assignment of treatments to experimental units in a randomized, controlled experiment. The good news is that the techniques used to sample without replacement can easily be extended to generate such random assignment plans.
It's probably a good time to remind you of the existence of the PLAN procedure. As I mentioned earlier, due to time constraints of the course and the complexity of the PLAN procedure, we will not use it to accomplish any of our random assignments. You should be aware, however, of its existence should you want to explore it on your own in the future.
Example 34.15 Section
Suppose we are interested in conducting an experiment so that we can compare the effects of two drugs (A and B) and one placebo on headache pain. We have 30 subjects enrolled in our study but need to determine a plan for randomly assigning 10 of the subjects to treatment A, 10 of the subjects to treatment B, and 10 of the subjects to the placebo. The following program does just that for us. That is, it creates a random assignment for 30 subjects in a completely randomized design with one factor having 3 levels:
DATA exper1;
DO Unit = 1 to 30;
OUTPUT;
END;
RUN;
DATA random1;
set exper1;
random=ranuni(27407349);
RUN;
PROC SORT data=random1;
by random;
RUN;
PROC FORMAT;
value trtfmt 1 = 'Placebo'
2 = 'Drug A'
3 = 'Drug B';
RUN;
DATA random1;
set random1;
if _N_ le 10 then group=1;
else if _N_ gt 10 and _N_ le 20 then group=2;
else if _N_ gt 20 then group=3;
format group trtfmt.;
RUN;
PROC PRINT data = random1 NOOBS;
title 'Random Assignment for CRD with One Factor';
RUN
Unit | random | group |
---|---|---|
11 | 0.00602 | Placebo |
14 | 0.14366 | Placebo |
18 | 0.18030 | Placebo |
4 | 0.20396 | Placebo |
12 | 0.21271 | Placebo |
29 | 0.21515 | Placebo |
9 | 0.25440 | Placebo |
3 | 0.29567 | Placebo |
21 | 0.32816 | Placebo |
22 | 0.33889 | Placebo |
17 | 0.44446 | Drug A |
19 | 0.47514 | Drug A |
5 | 0.49087 | Drug A |
23 | 0.50231 | Drug A |
28 | 0.52765 | Drug A |
25 | 0.53381 | Drug A |
24 | 0.55448 | Drug A |
6 | 0.60245 | Drug A |
8 | 0.60772 | Drug A |
20 | 0.61191 | Drug A |
16 | 0.69616 | Drug B |
7 | 0.69824 | Drug B |
1 | 0.70305 | Drug B |
10 | 0.71145 | Drug B |
13 | 0.71217 | Drug B |
15 | 0.86676 | Drug B |
27 | 0.96330 | Drug B |
26 | 0.97864 | Drug B |
30 | 0.98660 | Drug B |
2 | 0.99081 | Drug B |
Okay, let's first launch and run the SAS program, so you can review the resulting output to convince yourself that the code did indeed generate the desired treatment plan. You should see that 10 of the subjects were randomly assigned to treatment A, 10 to treatment B, and 10 to the placebo.
Now, let's walk ourselves through the program to make sure we understand how it works. The first DATA step merely uses a simple DO loop to create a temporary data set called exper1 that contains one observation for each of the experimental units (in our case, the experimental units are subjects). The only variable in the data set, unit, contains an arbitrary label 1, 2, ..., 30 assigned to each of the experimental units.
The remainder of the code generates a random assignment. To do so, the code from Example 34.5 is simply extended. That is:
- The second DATA step uses the ranuni function to generate a uniform random number between 0 and 1 for each observation in the exper1 data set. The result is stored in a temporary data set called random1.
- The random1 data set is sorted in order of the random number.
- The third DATA step uses an IF-THEN-ELSE construct to assign the first ten units in sorted order to Group 1, the second ten to Group 2, and the last ten to Group 3.
- A FORMAT is defined to label the groups meaningfully.
- The final randomization list is printed.
Example 34.16 Section
To create a random assignment for a completely randomized design with two factors, you can just modify the IF statement in the previous example. The following program generates a random assignment of treatments to 30 subjects, in which Factor A has 2 levels and Factor B has 3 levels (and hence 6 treatments). The code is similar to the code from the previous example except the IF statement now divides the 30 subjects into 6 treatment groups and (arbitrarily) assigns the levels of factors A and B to the groups:
DATA random2;
set exper1;
random=ranuni(4901);
RUN;
PROC SORT data=random2;
by random;
RUN;
DATA random2;
set random2;
if _N_ le 5 then
do; factorA = 1; factorB = 1; end;
else if _N_ gt 5 and _N_ le 10 then
do; factorA = 1; factorB = 2; end;
else if _N_ gt 10 and _N_ le 15 then
do; factorA = 1; factorB = 3; end;
else if _N_ gt 15 and _N_ le 20 then
do; factorA = 2; factorB = 1; end;
else if _N_ gt 20 and _N_ le 25 then
do; factorA = 2; factorB = 2; end;
else if _N_ gt 25 and _N_ le 30 then
do; factorA = 2; factorB = 3; end;
RUN;
PROC PRINT data = random2;
title 'Random Assignment for CRD with Two Factors';
RUN;
Obs | Unit | random | factorA | factorB |
---|---|---|---|---|
1 | 9 | 0.04052 | 1 | 1 |
2 | 21 | 0.04733 | 1 | 1 |
3 | 17 | 0.07038 | 1 | 1 |
4 | 20 | 0.11335 | 1 | 1 |
5 | 19 | 0.12459 | 1 | 1 |
6 | 7 | 0.14093 | 1 | 2 |
7 | 29 | 0.23206 | 1 | 2 |
8 | 10 | 0.24267 | 1 | 2 |
9 | 14 | 0.27161 | 1 | 2 |
10 | 26 | 0.28117 | 1 | 2 |
11 | 4 | 0.31276 | 1 | 3 |
12 | 18 | 0.34512 | 1 | 3 |
13 | 15 | 0.37393 | 1 | 3 |
14 | 28 | 0.37724 | 1 | 3 |
15 | 2 | 0.40480 | 1 | 3 |
16 | 6 | 0.42829 | 2 | 1 |
17 | 23 | 0.47371 | 2 | 1 |
18 | 11 | 0.48031 | 2 | 1 |
19 | 13 | 0.48552 | 2 | 1 |
20 | 12 | 0.48943 | 2 | 1 |
21 | 1 | 0.50155 | 2 | 2 |
22 | 3 | 0.53892 | 2 | 2 |
23 | 16 | 0.54762 | 2 | 2 |
24 | 24 | 0.69272 | 2 | 2 |
25 | 30 | 0.74252 | 2 | 2 |
26 | 5 | 0.77423 | 2 | 3 |
27 | 27 | 0.80270 | 2 | 3 |
28 | 8 | 0.82113 | 2 | 3 |
29 | 25 | 0.84338 | 2 | 3 |
30 | 22 | 0.95571 | 2 | 3 |
First, my apologies for the formatting that makes the IF-THEN-ELSE statement a little difficult to read. I needed to format it as such so that I could easily capture the image of the program for you.
Again, it's probably best if you first launch and run the SAS program, so you can review the resulting output to convince yourself that the code did indeed generate the desired treatment plan. You should see that five of the subjects were randomly assigned to the A=1, B=1 group, five to the A=1, B=2 group, five to the A=1, B=3 group, and so on.
Then, if you compare the code to the code from the previous example, the only substantial difference you should see is the difference between the two IF statements. As previously mentioned, the IF statement here divides the 30 subjects into 6 treatment groups and (arbitrarily) assigns the levels of factors A and B to the groups:
Example 34.17 Section
Thus far, our random assignments have not involved dealing with a blocking factor. As you know, it is natural in some experiments to block some of the experimental units together in an attempt to reduce unnecessary variability in your measurements that might otherwise prevent you from making good treatment comparisons. Suppose, for example, that your workload would prevent you from making more than nine experimental measurements in a day. Then, it would be a good idea then to treat the day as a blocking factor. The following program creates a random assignment for 27 subjects in a randomized block design with one factor having three levels.
DATA exper2 (drop = j);
DO block = 1 to 3;
DO j = 1 to 9;
if block = 1 then do; unit = j; output; end;
else if block = 2 then do; unit = j + 9; output; end;
else if block = 3 then do; unit = j + 18; output; end;
END;
END;
RUN;
PROC PRINT data=exper2; title 'EXPER2: Definition of Experimental Units'; RUN;
DATA random3;
set exper2;
random=ranuni(7214508);
RUN;
PROC SORT data=random3; by block random; RUN;
DATA random3;
set random3;
by block;
if first.block then k=0;
else k=k+1;
if k in (0,1,2) then trt=1;
else if k in (3,4,5) then trt=2;
else if k in (6,7,8) then trt=3;
retain k;
RUN;
PROC PRINT data=random3 noobs;
title 'Random Assignment for RBD: Sorted in BLOCK-TRT Order';
RUN;
PROC SORT data=random3; by block unit; RUN;
PROC PRINT data=random3 noobs;
title 'Random Assignment for RBD: Sorted in BLOCK-UNIT Order';
RUN;
Again, my apologies about the formatting that makes the program a little more difficult than usual to read. I needed to format it as such so that I could easily capture the image of the program for you.
It's probably going to be best if you first launch and run the SAS program, so you can first review the contents of the initial exper2 data set:
EXPER2: Definition of Experimental Units
Obs | block | unit |
---|---|---|
1 | 1 | 1 |
2 | 1 | 2 |
3 | 1 | 3 |
4 | 1 | 4 |
5 | 1 | 5 |
6 | 1 | 6 |
7 | 1 | 7 |
8 | 1 | 8 |
9 | 1 | 9 |
10 | 2 | 10 |
11 | 2 | 11 |
12 | 2 | 12 |
13 | 2 | 13 |
14 | 2 | 14 |
15 | 2 | 15 |
16 | 2 | 16 |
17 | 2 | 17 |
18 | 2 | 18 |
19 | 3 | 19 |
20 | 3 | 20 |
21 | 3 | 21 |
22 | 3 | 22 |
23 | 3 | 23 |
24 | 3 | 24 |
25 | 3 | 25 |
26 | 3 | 26 |
27 | 3 | 27 |
and then the resulting output that contains the desired treatment plan... first in block-treatment order:
Random Assignments for RBD: Sorted in BLOCK-TRT order
block | unit | random | k | trt |
---|---|---|---|---|
1 | 5 | 0.17083 | 0 | 1 |
1 | 8 | 0.18781 | 1 | 1 |
1 | 6 | 0.19400 | 2 | 1 |
1 | 9 | 0.40043 | 3 | 2 |
1 | 7 | 0.58852 | 4 | 2 |
1 | 4 | 0.60226 | 5 | 2 |
1 | 3 | 0.65488 | 6 | 3 |
1 | 1 | 0.79768 | 8 | 3 |
1 | 2 | 0.79977 | 7 | 3 |
2 | 12 | 0.06810 | 0 | 1 |
2 | 13 | 0.08280 | 1 | 1 |
2 | 16 | 0.23191 | 2 | 1 |
2 | 15 | 0.27690 | 3 | 2 |
2 | 11 | 0.38198 | 4 | 2 |
2 | 14 | 0.667 | 5 | 2 |
2 | 18 | 0.84177 | 6 | 3 |
2 | 10 | 0.91906 | 7 | 3 |
2 | 17 | 0.93312 | 8 | 3 |
3 | 21 | 0.09791 | 0 | 1 |
3 | 23 | 0.11455 | 1 | 1 |
3 | 22 | 0.21569 | 2 | 1 |
3 | 20 | 0.30461 | 3 | 2 |
3 | 26 | 0.30534 | 4 | 2 |
3 | 27 | 0.32876 | 5 | 2 |
3 | 24 | 0.46627 | 6 | 3 |
3 | 25 | 0.74756 | 7 | 3 |
3 | 19 | 0.91401 | 8 | 3 |
and then in block-unit order:
Random Assignments for RBD: Sorted in BLOCK-UNIT order
block | unit | random | k | trt |
---|---|---|---|---|
1 | 1 | 0.79768 | 8 | 3 |
1 | 2 | 0.79977 | 7 | 3 |
1 | 3 | 0.65488 | 6 | 3 |
1 | 4 | 0.60226 | 5 | 2 |
1 | 5 | 0.17083 | 0 | 1 |
1 | 6 | 0.19400 | 2 | 1 |
1 | 7 | 0.58852 | 4 | 2 |
1 | 8 | 0.18781 | 1 | 1 |
1 | 9 | 0.40043 | 3 | 2 |
2 | 11 | 0.38198 | 4 | 2 |
2 | 10 | 0.91906 | 7 | 3 |
2 | 12 | 0.06810 | 0 | 1 |
2 | 13 | 0.08280 | 1 | 1 |
2 | 14 | 0.667 | 5 | 2 |
2 | 15 | 0.27690 | 3 | 2 |
2 | 16 | 0.23191 | 2 | 1 |
2 | 17 | 0.93312 | 8 | 3 |
2 | 18 | 0.84177 | 6 | 3 |
3 | 19 | 0.91401 | 8 | 3 |
3 | 20 | 0.30461 | 3 | 2 |
3 | 21 | 0.09791 | 0 | 1 |
3 | 22 | 0.21569 | 2 | 1 |
3 | 23 | 0.11455 | 1 | 1 |
3 | 24 | 0.46627 | 6 | 3 |
3 | 25 | 0.74756 | 7 | 3 |
3 | 26 | 0.30534 | 4 | 2 |
3 | 27 | 0.32876 | 5 | 2 |
As you can see, the exper2 data set is created to contain one observation for each of the experimental units (27 subjects here). The variable unit contains an arbitrary label (1, 2, ..., 30) assigned to each of the experimental units. The variable block, which identifies the block number (1, 2, and 3), divides the experimental units into three equal-sized blocks of nine.
Now, to create the random assignment:
- We use the ranuni function to generate a uniform random number between 0 and 1 for each observation.
- Then, within each block, we sort the data in order of the random number.
- Then, we create a counter variable to count the number of observations within each block: for the first observation within each block ("if first.block"), we set the counter (k) to 0; otherwise, we increase the counter by 1 for each observation within the block. (For this to work, we must retain k from iteration to iteration).
- Using an IF-THEN-ELSE construct, within each block, assign the first three units in sorted order (k=0,1,2) to group 1, the second three (k=3,4,5) to group 2, and the last three (k=6,7,8) to group 3.
Depending on how the experiment will be conducted, you can print the random assignment in different orders:
- First, the randomization is printed in order of treatment within each block. This will accommodate experiments for which it is natural to perform the treatments in groups on the randomized experimental units.
- Then, the randomization is printed in order of units within the block. This will accommodate experiments for which it is natural to perform the treatments in random order on consecutive experimental units.