Google SAS Search

Add to Google

Wednesday, December 21, 2005

Quantum missing

The other day I was pulling into one of my local surfing spots to watch one of the larger swells of the season roll through and I got a call on the cell phone from my wife. After exchanging the usual pleasentries she asked me if I knew how to get the maximum missing value out of a set of missing values. WTF?
For reasons that only really really smart people can comprehend, her organization sometimes uses different "values" of missing to enumerate different reasons for the missing value. Are you with me? Something along the lines of:


select( q1a )
when('ONE') q1s = 1 ;
when('TWO') q1s = 2 ;
when('DK') q1s = .d ;
when('RF') q1s = .r ;
otherwise q1s = . ;
end;


Ostensibly this is used for creating the variables that will eventually be used in statistics.
Cause as missings, they are automatically excluded by proc calculations; but you can still see "why" it's missing. I have to say, I don't know if it's a neat-o trick or a classic abuse of language potential (just cause you CAN do it doesn't mean it's a GOOD idea), but my wife is much more pragmatic than I and didn't care to hear my theoretical musings on storing multiple values in what most of us would consider a single value-- missing. She just wanted to know: did I have an answer?

Well, the max() function returns a missing value if any of it's arguments are missing so that was no good. But as luck would have it the max operator will treat a missing value as a real value. (Which seems quite opposite of the sum() function and + operator. . .) And not only that, but the SAS documentation actually includes an order of missing values. Going smallest to largest:
._
.
.A - .Z

So the simple answer to her complicated question was:

maxMissingValue = m1 <> m2 <> m3 ; 


Of course, I did not know the answer when she called and at the time I was much more interested in the overhead bombs that were breaking outside. I mean, these were some seriously mind numbing big waves. . . So I made some lame joke about how you can't know the missing value until you collapse the missing value potential wave into a singularity event through observation, blah blah blah, uh I have no idea honey.

Thursday, December 01, 2005

Goto Memories

December already?! Seems like only yesterday I was dressing my little baby up for her first Halloween. And now we've already entered the *most wonderful time of the year*. A lot of people complain about the stores setting up their Christmas displays too early. Me? I like it. Bring on the displays! I like Christmas. I like winter. I like the holidays. I just wish I could get over this head cold. You know when you get a cold and it seems like your nose will never return to normal? Like you can't even remember what it was like to not have a cough? I hate having a cold.

When I was a kid my brother and I saved all our money one summer and bought ourselves a Commodore 64. That was the best Christmas ever. I would stay up all night programming in BASIC to get a smiley face sprite to bounce around the screen. I had to save my programs to cassette tape because we hadn't bought a disk drive yet. They were really expensive back then. I wish I had one of those cassette tapes now. If you played it back in the stereo it would make this weird analog warbly noise. I'd love to see what my BASIC code looked like. It'd probably be incomprehensible to me now. I remember I used to like cramming as many statements as possible onto one line and I think I used a lot of GOTO statements. Terrible, terrible bad habits for a 10 year old to be picking up!

So where am I going with this? This is a SAS blog after all, not a commodore blog. I was supposed to share some nugget of wisdom about programming in SAS but instead started rambling about BASIC and GOTO statements. Must be the cough syrup.

I still use GOTO statements today. Do you? They can come in quite handy for SAS/MACRO. Consider the following code. I know it's not a new technique, but it's useful and worth sharing.


* just two little data sets to work with;
data base;
input key;
datalines;
1
2
3
4
;

data newRecords;
input key;
datalines;
1
2
;

*************************************;

%macro earlyTermination();

%* Suppose you wanted to merge some data and see if
there were any records that didnt match. Then you
want to do some processing on those non-matching records.
Otherwise if there were no non-matches you dont want
to do any more processing.;

proc sort data = base;
by key;
run;

proc sort data = newRecords;
by key;
run;

data nonMatches;
merge base(in=base)
newRecords(in=newRecords);
by key;
if newRecords and not base then output;
run;

%* check to see if there are any records in nonMatches;
%let dsid = %sysfunc( open( nonMatches ) );
%let nobs = %sysfunc( attrn( &DSID, nobs ) );
%let rc = %sysfunc( close( &DSID ) );

%if &NOBS = 0 %then %goto done;

%* otherwise do some processing with the
nonMatches
.
.
.;

%put There were &NOBS non-matching records;

%done:
%mend earlyTermination;

%earlyTermination;


In this case we goto an empty label. But there could have been some statements after %DONE. It's important to note however, that the %DONE label will be executed NO MATTER WHAT.

Happy programming.