Discussion:
Permuted Block Randomization with PROC PLAN
(too old to reply)
Haris
2007-03-28 01:42:36 UTC
Permalink
I've been trying to generate a randomization schedule for permuted-
block randomization schedule and am having no luck with PROC PLAN. I
did it manually before, but was hoping for simplification.

I am looking to assign patients in a randomized multi-site trial to
two treatments (1 and 2). The plan calls for permuted-block
randomization with 2, 4 and 6 patients per block. A condition is
imposed where within each block, equal number of patients gets
assigned to each group, e.g. 1,1,2,2 in the block of 4 or 1,1,2,2,1,2
in the block of 6.

First, each site gets assigned multiple of block orders first. There
are six possible combinations of the three block sizes and each
triplet is good to randomize 12 patients. Let's say that I need to
randomize 120 patients which means that I need 10 random 3-block-size
orders per site. I think I can figure out how to do this part in PROC
PLAN on my own.

Next, I need to randomly fill in the actual treatment assignment
within each block. There are only two orders for the block of two
(1,2 and 2,1), 6 permutations in the block of 4 etc. So if the first
random block-order is 2-4-6, I need to randomly pick 1,2 or 2,1 for
block of 2; 1122, 2211,1221, 2112, 1212, or 2121 for block of 4, etc.
Is there a way to fill these values into a neat table with Proc PLAN?
Haris
2007-03-28 18:39:55 UTC
Permalink
Here's what I had to resort to in order to accomplish the task:


/* Generate random numbers for:
/* 1. Block orders (2, 4, and 6 subjects)
/* 2. Assignment orders within blocks of different sizes
/****************************************************************/
proc plan seed=32807;
factors Site = 100 ordered
Block = 10 ordered
BlockO = 1 of 6
Two = 1 of 2
Four = 1 of 6
Six = 1 of 18 ;
output out=a Two cvals=('EC' 'CE')
Four cvals=('EECC' 'ECEC' 'ECCE' 'CEEC' 'CECE' 'CCEE')
Six cvals=('EECECC' 'EECCEC' 'EECCCE'
'ECEECC' 'ECECEC' 'ECECCE'
'CEEECC' 'CEECEC' 'CEECCE'
'ECCEEC' 'ECCECE' 'ECCCEE'
'CECEEC' 'CECECE' 'CECCEE'
'CCEEEC' 'CCEECE' 'CCECEE') ;

/* Join within-block randomization assignments */
/* and random within-block orders */
data b ;
retain Site Block Order ;
length Order $12. ;
set a ;
if BlockO=1 then Order=cats(Two, Four, Six) ;
if BlockO=2 then Order=cats(Two, Six, Four) ;
if BlockO=3 then Order=cats(Four, Two, Six) ;
if BlockO=4 then Order=cats(Four, Six, Two) ;
if BlockO=5 then Order=cats(Six, Two, Four) ;
if BlockO=6 then Order=cats(Six, Four, Two) ;
keep Site Block Order ;

/* Transpose the file to create one record per site */
proc transpose data=b out=c (drop=_name_) Prefix=Block ;
var Order ;
by Site ;

/* Concatenate 10 randomization blocks */
/* into a single string of group assignments */
data d ;
retain Site Order ;
length Order $131. ;
set c ;
Order = catx (' ', of Block1-Block10) ;
drop Block1--Block10 ;
run ;

I wonder if there is an easier way.
data _null_;
2007-03-29 12:20:31 UTC
Permalink
I don't have anything to offer. But I have a question. If the
sequences 'EECC' and 'CCEE' are good then why not 'EEECCC','CCCEEE'.
When I use a program to compute the sequences I get 20 for the number
of sequences for block size 6.

data work.p4;
array _p[4] $1 ('E' 'E' 'C' 'C');
length seq $16.;
do _n_=1 to fact(dim(_p));
call allperm(_n_, of _p[*]);
seq = cats(of _p[*]);
output;
end;
keep seq;
run;
proc sort nodupkey force;
by seq;
run;
proc print;
run;

data work.p6;
array _p[6] $1 ('E' 'E' 'E' 'C' 'C' 'C');
length seq $16.;
do _n_=1 to fact(dim(_p));
call allperm(_n_, of _p[*]);
seq = cats(of _p[*]);
output;
end;
keep seq;
run;
proc sort nodupkey force;
by seq;
run;
proc print;
run;
data work.control;
fmtname = 'BS4_'; /*block size 4*/
type = 'N';
length start 8 label $40;
do until(eof);
set work.p4 end=eof;
start + 1;
label = seq;
output;
end;
eof = 0;
fmtname = 'BS6_'; /*block size 6*/
start = 0;
do until(eof);
set work.p6 end=eof;
start + 1;
label = seq;
output;
end;
stop;
run;
proc format fmtlib cntlin=control;
run;
/* 1. Block orders (2, 4, and 6 subjects)
/* 2. Assignment orders within blocks of different sizes
/****************************************************************/
proc plan seed=32807;
factors Site = 100 ordered
Block = 10 ordered
BlockO = 1 of 6
Two = 1 of 2
Four = 1 of 6
Six = 1 of 18 ;
output out=a Two cvals=('EC' 'CE')
Four cvals=('EECC' 'ECEC' 'ECCE' 'CEEC' 'CECE' 'CCEE')
Six cvals=('EECECC' 'EECCEC' 'EECCCE'
'ECEECC' 'ECECEC' 'ECECCE'
'CEEECC' 'CEECEC' 'CEECCE'
'ECCEEC' 'ECCECE' 'ECCCEE'
'CECEEC' 'CECECE' 'CECCEE'
'CCEEEC' 'CCEECE' 'CCECEE') ;
/* Join within-block randomization assignments */
/* and random within-block orders */
data b ;
retain Site Block Order ;
length Order $12. ;
set a ;
if BlockO=1 then Order=cats(Two, Four, Six) ;
if BlockO=2 then Order=cats(Two, Six, Four) ;
if BlockO=3 then Order=cats(Four, Two, Six) ;
if BlockO=4 then Order=cats(Four, Six, Two) ;
if BlockO=5 then Order=cats(Six, Two, Four) ;
if BlockO=6 then Order=cats(Six, Four, Two) ;
keep Site Block Order ;
/* Transpose the file to create one record per site */
proc transpose data=b out=c (drop=_name_) Prefix=Block ;
var Order ;
by Site ;
/* Concatenate 10 randomization blocks */
/* into a single string of group assignments */
data d ;
retain Site Order ;
length Order $131. ;
set c ;
Order = catx (' ', of Block1-Block10) ;
drop Block1--Block10 ;
run ;
I wonder if there is an easier way.
Haris
2007-03-29 15:23:20 UTC
Permalink
You are correct, _null_, but we decided that 6 patients in a row
potentially going to the same group was too much and did not use
permutations CCCEEE and EEECCC.

Really fancy code, though :)

Loading...