Thursday, May 24, 2012

To flag Baseline records

As an example, the Baseline value for one assessment here is defined as the last non-missing measurement taken on or before the day of the first dosing of study drug.

Different programmers use different approaches to flag Baseline records. I used two steps (using LB domain in SDTM as an example):
1) To sort the assessment results in dataset LB througth PROC SORT by subject assessment date_time...;

PROC SORT DATA=lb;
  BY usubjid lbcat lbscat lbtestcd DESCENDING lbdtc;
RUN;

2) To flag the Baseline value with ABLFL='Y'.

 DATA lb(drop=flag); ** drop the temporary variable **;
  SET lb;
  BY usubjid lbcat lbscat lbtestcd DESCENDING lbdtc;
   ** variable flag is used to identify if one test has ABLFL marked **;
  RETAIN flag;
   ** flag=0 indicating there is no ABLFL marked yet. **; 
  IF first.lbtestcd THEN flag=0;
  ** you can add more conditions in IF logic expressions. **;
  ** TRTSDT below has the first dosing dates. **;
  IF flag=0 and LBDT <= TRTSDT and LBSTRESN ne .THEN DO;
    ABLFL='Y'; ** ABLFL='Y' indicates the baseline record. **;
    flag=1; ** flag=1 indicating the ABLFL is marked. **;
  END;
RUN; 
 

Friday, May 11, 2012

pros and cons in IFN/IFC function

After one of my colleagues told me about IFN/IFC functions, I addicted to use them everywhere until I found some issues. Now, I still use them a lot but more carefully.

IFN and IFC functions have same syntax, only that IFN will return a numeric value and IFC will return a character value.

For an example, syntax of IFC function in SAS Help:
IFC(logical-expression, value-returned-when-true, value-returned-when-false <,value-returned-when-missing>) 

IFC evaluates the first argument, logical-expression. If logical-expression is true (that is, not zero and not missing), then IFC returns the value in the second argument. If logical-expression is a missing value, and you have a fourth argument, then IFC returns the value in the fourth argument. Otherwise, if logical-expression is false, IFC returns the value in the third argument.

It is similar to IF function in MS Excel, or conditional operator in other language. Actually, it is even better, because it could handle when logical expression is a missing value.

IFN/IFC functions are very useful for encoding, decoding, and flagging values.Like most of DATA step functions, they can be used in WHERE statement to simplify logic expressions, or in SQL statements and make PROC SQL more powerful. They will also save a lot of typing and SAS codes usually will be more neat and clean.

Two issues so far I found:
1) It seems that logical expression does not function like IF-THEN-ELSE statement.

For example, we have following IF-THEN-ELSE statement which will work fine.
a=0; b=10;
IF a ne 0 and b/a>0.1 THEN   c="b/a>0.1";

You will get c=" " without any complaints. I think, when SAS system finds a=0 and the logical expression is
"a ne 0 and ...", it will stop checking the rest of logical expression. So it won't reach b/a which is 10/0.


If you use IFC:
c=IFC(a ne 0 and b/a>0.1, "b/a>0.1", " ");
You will get error message:
NOTE: Division by zero detected at line 17 column 29.
a=0 b=10 c=  _ERROR_=1 _N_=1


2) It seems that all arguments are evaluated before it applies the function algorithm.
For example,
data _null_;
   a=0;
   b=ifn(a ne 0, 10/a, .);
   put a b;
run;

I expected that it would evaluate the logical expression and give me missing value directly. It actually gives me error message.
NOTE: Division by zero detected at line 3 column 17.
a=0 b= _ERROR_=1 _N_=1

If you use IF-THEN-ELSE statement, you will not get such message.

Another trick in IFC (I think it is a good) is that if length of the variable is not pre-defined, IFC will return a character value with length=200.
For example, a_var=IFC(1 = 2, 'TRUE', 'FALSE');
We may think, 'TRUE' has 4 characters, will 'FALSE" be truncated, and a_var="FALS"?
Actually, we will get a_var with length=200 and value="FALSE".

Thursday, May 10, 2012

A macro variable with "current date" in yymmdd10. format

You may already know that SAS system provides two automatic macro variables, &sysdate and &sysdate9, to contain the date that a SAS job or session began executing. Mot of the time, these two macro variables are good enough to be treated as current date. 

The issue I had is that these dates are in Date7. and Date9. format. I usually want to create folder/file names with dates in YYYY-MM-DD format, so that those folders/files could be sorted correctly. 

Here I present a simple way to create a macro variable &cdate with re-formatting &sysdate9 to YYYY-MM-DD format.

%let cdate=%sysfunc(putn("&sysdate9"d,yymmdd10.));
%put &cdate;

** Updated on 2012-06-05 **;
** If using today's date, instead of &sysdate or &sysdate9, Here is the codes **;
%let cdate=%sysfunc(date(),yymmdd10.);
%put &cdate;