Several months ago, I wrote a post on how to deal with decimal places when computing summary statistics for safety assessements like LB test, EG test and VS test. Comparing against multiple IF…ELSE… approach, the method introduced in that post indeed offers us much more conveniences. However, we need to round numeric values before putting them into character values sometimes.

Why do we need to use ROUND function?

For negative numbers, if we use a put function with a normal w.d format without a round function, the numbers will be rounded to zero. While at the same time, the minus sign will still be displayed (e.g. -0.0 or -0.00). Sometimes, our statisitician may require us to remove the minus sign (-). In this case, we have to use ROUND function before using PUT function.

It is well known that computers represent numbers by approximations. A loss of significant digits may happen. Thus two “same” numbers in different computers do not really equal to each other. For example, 0.2225 in my computer and 0.2225 in your computer are different. To test this inequality, you can subtract 0.2225 from your number, you may get a number that is less than 0. I may get postive number which implies that 0.2225 at my side is in fact large than 0.2225. In this situation, you cannot get the numbers matched by putting them into characters directly using PUT function. This is a common problem especially when computing Mean of safety assessments.  To fix this problem, we also have to use ROUND function before applying PUT function.

ROUND & PUTN together to simplify code

In our previous post, we have used PUTN to simplify our code and following figure show you how to simplify code further by applying ROUND and PUTN functions together.

Example of how to develop summary tables for ADLB

We still use dummy data and shell from our last post. Here is the full code from reading data into SAS and manipulating data.  we create three new variables rn1, rn2 and rn3 which will be used here as the second argument of ROUND function.

Click here to hide/show code


data adlb;
infile “D:\ADLB.txt”;
input USUBJID $ 1-7 TRT01A $ 9-20 TRT01AN 22 PARAM $ 25-41 PARAMN 43
AVISIT $ 45-60 AVISITN 62-65 AVALC $ 67-71 AVAL 73-76;
run;

data adlb;
set adlb;
if index(avalc,’.’)=0 then ln_ = 0;
else if index(avalc,’.’)>0 then ln_ = length(scan(strip(avalc),2,’.’));
run;

proc sort data = adlb; by paramn param descending ln_; run;
data adlb;
retain ln;
set adlb;
by paramn param descending ln_;
if first.paramn then ln = ln_;

ln1= strip(put((8 + ln*0.1),8.1));
ln2= strip(put((8 + ln*0.1 + 0.1),8.1));
ln3= strip(put((8 + ln*0.1 + 0.2),8.1));

rn1 = 0.1**ln;
rn2 = 0.1**(ln+1);
rn3 = 0.1**(ln+2);
run;

ods exclude all;
proc sort data = adlb; by paramn param ln1 ln2 ln3 rn1 rn2 rn3 avisitn avisit trt01an; run;
proc means data = adlb n nmiss mean std min max median noprint;
by paramn param ln1 ln2 ln3 rn1 rn2 rn3 avisitn avisit trt01an ;
var aval;
output out = dist(drop = _type_ _freq_) n= n nmiss = nmiss mean = mean std = std
min=min max=max median = median;
run;
ods exclude none;

proc sort data = dist out= dummy(keep = paramn param ln1 ln2 ln3 rn1 rn2 rn3 avisitn avisit) nodupkey;
by param avisitn avisit; run;
data dummy;
set dummy;
do trt01an = 1 to 2;
n = .; nmiss = .; mean = .; std = .; min = .; max = .; median = .;
output;
end;
run;

proc sort data = dummy; by paramn param ln1 ln2 ln3 rn1 rn2 rn3 avisitn avisit trt01an; run;
proc sort data = dist; by paramn param ln1 ln2 ln3 rn1 rn2 rn3 avisitn avisit trt01an; run;

data dist;
length nn nnmiss $200. msd $200. med $200. mia $200.;
update dummy dist;
by paramn param ln1 ln2 ln3 rn1 rn2 rn3 avisitn avisit trt01an;

if n ne . then nn = strip(put(n,8.0));
else nn = “-“;

if nmiss ne . then nnmiss = strip(put(nmiss,8.0));
else nnmiss = “-“;

if mean ne . and std ne . then
msd = strip(putn(round(mean,rn2),ln2))||” (“||strip(putn(round(std,rn3),ln3))||”)”;
else if mean ne . and std eq . then
msd = strip(putn(round(mean,rn2),ln2));
else msd = “-“;

if median ne . then med = strip(putn(round(median,rn2),ln2));
else med = “-“;

if min ne . and max ne . then mia = strip(putn(round(min,rn1),ln1))||”, “||strip(putn(round(max,rn1),ln1));
else mia = “-“;
run;
data dat;
length col1 $200. ;
set dist;
array col{5} nn msd med mia nnmiss;
do i = 1 to 5;
seq = i + 1 ;
count = col{i};
id = trt01an + 1;
if i = 1 then col1 = “\li400 n”;
else if i = 2 then col1 = “\li400 Mean ” ||”(SD)”;
else if i = 3 then col1 = “\li400 Median”;
else if i = 4 then col1 = “\li400 Min, Max”;
else col1 = “\li400 Missing”;
output;
end;
keep seq col1 count paramn param avisitn avisit trt01an id;
run;

proc sort data = dat; by paramn param avisitn avisit seq col1 id ; run;
proc transpose data = dat out=final(drop=_name_) prefix = col;
by paramn param avisitn avisit seq col1 ;
id id;
var count;
quit;


Here is the final output which is the same as that in our previous post.