| David Franklin, Blog | |
| 2007 Archive | |
| Back | dfranklinnh@gmail.com |
|
JanuaryWelcome to 2007! I hope the New Year was good to you. This month I will look at rounding numbers and four different functions that SAS gives to rounding. The four that will be looked at here are:
The following code and output demonstrates the output of certain values of x when the functions above are applied to the value x: data x;
infile cards;
input x;
fl=floor(x);
cl=ceil(x);
ro=round(x);
in=int(x);
label fl='floor(x)'
cl='ceil(x)'
ro='round(x)'
in='int(x)';
cards;
1.6
1.5
1.4
1.0
0.0
-1.0
-1.4
-1.5
-1.6
;
run;
title1 "x Rounded Using Four SAS Rounding Functions";
proc print data=x label;
run;
=== Output ===
x Rounded Using Four SAS Rounding Functions
Obs x floor(x) ceil(x) round(x) int(x)
1 1.6 1 2 2 1
2 1.5 1 2 2 1
3 1.4 1 2 1 1
4 1.0 1 1 1 1
5 0.0 0 0 0 0
6 -1.0 -1 -1 -1 -1
7 -1.4 -2 -1 -1 -1
8 -1.5 -2 -1 -2 -1
9 -1.6 -2 -1 -2 -1
Have a very happy 2007. See you in February. FebruaryThis month is a quick look at the trigonometric functions available in SAS. Function Trigonometric Inverse Hyperbolic
--------------------------------------------
Sine SIN ARSIN SINH
Cosine COS ARCOS COSH
Tangent TAN ATAN TANH
Note that all angles that are entered using the trigonometric functions are in radians, i.e. if the angle is in degrees then this value must be multiplied by PI/180 before using the function. The following example demonstrates the use of the SIN function and returning its inverse: data _null_;
pi=constant('PI');
angle=30*PI/180;
sinx=sin(angle);
arsinx=arsin(sinx)*180/pi;
put angle= sinx= arsinx= pi=;
run;
produces the output in the log angle=0.5235987756 sinx=0.5 arsinx=30 pi=3.1415926536 Note the use of the CONSTANT function - this function accesses certain mathematical constants, including PI, that are set within SAS. Before SAS version 8 the constant for PI did not exist so alternates were used to set a value for PI, namely setting PI to a value say 3.14159, or if more accuracy was needed setting the value to the result of ARCOS(-1). MarchOccasionally it is necessary to cleanup old datasets in a directory based on a date. The following SAS code is an example where datasets in the directory referenced by the LIBNAME OLDDATA that are older than 15MAR2007 are deleted: %let dslist=%str();
proc sql;
select memname into :dslist separated by ' '
from sashelp.vtable
where libname='OLDDATA' and
datepart(crdate) "15MAR2007"d;
quit;
run;
proc datasets library="OLDDATA" nolist nodetails;
delete &dslist
quit;
run;
This code can be modified to any datasets in a specified directory as well as and date and/or time that the user may choose. AprilOccasionally the dataset I am working with will have labels and formats associated with it but I want to clear these attributes and just work with the raw data. The following example of code removes all labels and formats for the dataset DEMO in the directory referenced by the LIBNAME WORK: proc datasets lib=work nolist;
modify demo;
attrib _all_ label=''; *Remove labels;
format _all_; *Remove formats;
quit;
run;
Conference season is starting this month with the SAS Global Forum in Orlando, FL, USA, followed by the SAS Forum in Stockholm, Sweden in May, and PharmaSUG in Denver, CO, USA in June. While these are the big ones there are a number of other local and regional meetings throughout the world at different times of the year. I urge you all to support your local, regional or national group during the coming year. MayWant to know which SAS modules are loaded on your system? Try the following SAS code and look at the log: proc setinit noalias;
run;
Not every site has all the SAS modules, if fact there are very few - at last count there were 30+ separate modules available and the odds that all the SAS modules are on your system is remote. This is important as sometimes when I am creating an output I want to test which SAS modules are loaded on a system, and depending on what is available the program will do one process or another. You can test if a module is loaded or not using either the SYSPROD or %SYSPROD functions. The following example demonstrates its use: %if %sysprod(STAT)=1 %then %do;
%*STAT module loaded then run macro using PROC TTEST;
... more SAS statements ...
%end;
%else %do;
%*STAT module not loaded - use TTEST from R;
... more SAS statements ...
%end;
JuneTo many, the PROC MEANS and PROC SUMMARY SAS procedures are the same. There are however two differences. The first difference is that the SUMMARY procedure does have as default to print no output to an output file while the MEANS procedure does by default. The option that controls this is PRINT/NOPRINT so it is possible to print the output from the SUMMARY procedure and have no output from the MEANS procedure. The second difference is not widely known but it is a useful. When the VAR statement is missing in the MEANS procedure analysis is carried out on all numeric variables, as shown in the following example (output below):= data vitals;
infile cards;
input patid $3. heart_rate
temperature trtcd $1.;
cards;
001 72 35.8 A
002 80 36.4 B
003 99 36.6 A
;
run;
proc means data=vitals nway;
class trtcd;
run;
The SAS System
The MEANS Procedure
N
trtcd Obs Variable N Mean Std Dev Minimum Maximum
--------------------------------------------------------------------------
3 3 heart_rate 3 2.0000000 1.0000000 1.0000000 3.0000000
temperature 3 83.6666667 13.8684294 72.0000000 99.0000000
--------------------------------------------------------------------------
However, what happens when the SUMMARY procedure is used instead on the same data? proc summary data=vitals nway print;
class trtcd;
run;
The SAS System
The SUMMARY Procedure
N
trtcd Obs
------------
A 2
B 1
------------
Notice that the only result that came out from the SUMMARY procedure was the number of observations from each treatment group, similar to what the FREQ procedure will produce. The same result will prevail if the only variables in the VITALS dataset were PATID and TRTCD, that is only the character variables. So what does this finding mean? In most cases SAS programmers use the FREQ procedure for frequency counts and the MEANS procedure for summary statistics however these two sets of statistics most commonly carried out can be done by one procedure. A possible macro for calculating both from one procedure is given below: %macro summstat(dsin=,
/*Input file -REQUIRED*/
dsout=,
/*Results filst -REQUIRED*/
classvar=,
/*Class Variable(s) -REQUIRED*/
vvars=,
/*Analysis Variables, only if
descriptive statistics
requested. Can use one or
numeric variable names or
_NUMERIC_ for all numeric
variables. AUTONAME option will
set variable names in output
file*/
outprt=NOPRINT
/*Output to listings file.
Values: PRINT|NOPRINT*/
);
proc summary data=&dsin nway &outprt
class &classvar
%if (&vvars ne ) %then %do;
var &vvars
output out=&dsout (drop=_type_ _freq_)
n= mean= std= median= min= max=
/autoname;
%end;
%else %do;
output out=&dsout
(drop=_type_
rename=(_freq_=N));
%end;
run;
%mend summstat;
If anyone is going to PharmaSUG in Denver, I hope to see you there. JulyThe COLLATE function is a strange one but can fill gap where you have to produce a string of characters in a sequence. The syntax for the COLLATE function is: COLLATE(start,stop,length); Where start is the starting character, stop is the ending character, and length is the number of characters from the starting character -- if a start, stop and length are defined then length is ignored. The following example produces the characters A to Z to a variable called CHAR: 69 data _null_;
70 char=collate(rank('A'),rank('Z'));
71 put char=;
72 run;
char=ABCDEFGHIJKLMNOPQRSTUVWXYZ
Note the use of the RANK function that converts the character to the character code so that we do not have to work out the code for 'A' and 'Z' before the step. We could have easily written another way using the following code: 73 data _null_;
74 char=collate(rank('A'),,26);
75 put char=;
76 run;
char=ABCDEFGHIJKLMNOPQRSTUVWXYZ
AugustYou have just received a dataset from a European client and you open the dataset in SAS Viewer and note that the dates are in dd/mm/yy format, not what you want for your report in New York this morning which is mm/dd/yy format. Don't fret. A date that is stored in a numeric variable inside a SAS dataset is the number of days since January 1, 1960, so internally to the variable (without the FORMAT specification) it does not care what format you what it displayed in. To solve the problem, the display of the date can be set to mm/dd/yy format using the format MMDDYY8. that can be put in a PRINT or REPORT procedure anywhere, using the following statement: FORMAT MMDDYY8. As a useful tip, an international standard that has been adopted is to have the dates in yyyy-mm-dd format (SAS format YYMMDD10.) and avoids the confusion between US mm/dd/yyyy format (SAS format MMDDYY8.) and European format dd/mm/yyyy (SAS format DDMMYY8.), or adopt the standard SAS date format ddMMMyyyy format (SAS format DATE9.) for variables containing dates within your dataset. SeptemberSince when does a null string have a length of 1? This question is an interesting one and is solved by using the correct length function. The SAS documentation as the following for the length related functions:
So lets look at what each function brings up if we have a string with text and a second with nothing in it, noting that both are defined with a length of 30 characters: 357 data _null_; 358 length TextStr1 TextStr2 $30; 359 TextStr1='32 Windsor Gardens, London'; 360 TextStr2=' '; 361 LENGTH1=length(TextStr1); 362 LENGTHC1=lengthc(TextStr1); 363 LENGTHM1=lengthm(TextStr1); 364 LENGTHN1=lengthn(TextStr1); 365 LENGTH2=length(TextStr2); 366 LENGTHC2=lengthc(TextStr2); 367 LENGTHM2=lengthm(TextStr2); 368 LENGTHN2=lengthn(TextStr2); 369 put TextStr1= / 370 LENGTH1= LENGTHC1= LENGTHM1= LENGTHN1= / 371 TextStr2= / 372 LENGTH2= LENGTHC2= LENGTHM2= LENGTHN2=; 373 run; TextStr1=32 Windsor Gardens, London LENGTH1=26 LENGTHC1=30 LENGTHM1=30 LENGTHN1=26 TextStr2= LENGTH2=1 LENGTHC2=30 LENGTHM2=30 LENGTHN2=0 It is interesting to note that the LENGTHN function actually got it right in both cases, particularly when you consider that the second string, variable TextStr2, was set to null. OctoberThis can be quite tricky, and does depend on where in the datastep the RENAME statement is placed. Lets look at the following example: *** Creating a dataset;
data ourdata;
infile cards;
input x y z;
cards;
1 2 3
4 5 6
;
run;
*** Modifying the variable names;
data ourdata_modified;
set ourdata (rename=(x=a));
rename y=b;
if a=1 then do;
*More steps;
end;
if y=5 then do;
*More steps;
end;
run;
In the example, the variable x is renamed to a PRIOR to entry into the datastep, meaning that the variable a is known and can be manipulated within the step. This is different to the variable y - this is renamed as the observation is passed into the dataset OURDATA_MODIFIED, meaning that the variable y is still available inside the datastep for manipulation. NovemberSometimes we want to know if a variable is missing or blank and carry out some action based on that condition enter stage right the MISSING function. The MISSING function returns a 1 (true) or 0 (false) if a numeric or character string is missing or blank. The following code demonstrates its use: 189 data _null_; 190 length string1 string2 $30; 191 string1='THE COW JUMPED OVER THE MOON'; 192 string2=' '; 193 missing1=missing(string1); 194 missing2=missing(string2); 195 put missing1= string1= / 196 missing2= string2=; 197 run; missing1=0 string1=THE COW JUMPED OVER THE MOON missing2=1 string2= DecemberLast month we looked at the MISSING function, this month we look at the MISSING Routine. This routine is useful if you are filling a variable or variables with missing values. Lets take for example the following fragment of code: Sex=.; Race=; In the example, the variables SEX and RACE are set to blank we have know if the variables are character or numeric. In SAS there is a way of setting these variables to blank regardless of whether they are numeric or character, SAS works out whether the variables are character or numeric: CALL MISSING(sex,race); See you all next year. |