On Thu, 19 Nov 2009 16:27:52 -0500, Ian Whitlock <iw1sas@GMAIL.COM> wrote:
>Chang,
>I think we pretty much agree, but I couldn't resist embedding some
>comments
>below.
>Ian Whitlock
Hi, Ian,
It is great that we agree!!
>***Chang, that is precisely the difference in point of view between a
>good
>programmer and a programming statistician. The latter is more
>interested
>in statistics and the former in the "proper level of generalization". I
>will do anything to get that proper level of generalization.
I have a bit different opinion, probably due to my own experience. My boss
happens to be an accomplished statistician working at the bleeding edge of a
statistical field, but at the same time a great coder who is well versed in
both statistical and general (web and application) programming and is an
expert in many computer languages including C# and R. So, I don't believe
the stereotypes like "statisticians are not good programmers" or
"programmers don't even know what the chi-squared is."
Despite coder's love of "clean" code, software itself does not have any
intrinsic value at all. It is not an art piece, nor a great poem. Its value
lies on what it does when it is run. In this regard, both programmer and
statistician sas users have the same goal -- writing a sas code which does
what they intend it to do. And regardless of their job title, as Peter says,
some people have better skills in coding than others. And everybody will
benefit by learning best practices which are proven to be useful.
....
>> proc logistic ...
>> model dep = ... addvar1;
>> oddsratio addvar1;
>> run;
>> model dep = ... addvar2;
>> oddsratio addvar2;
>> run;
>> model dep = ... addvar3;
>> oddsratio addvar3;
>> run;
>> quit;
>
>***Agreed, but I would have used
> %model (addvar)
Well, this is all rather hypothetical since proc logistic does not allow
multiple model statements. but Peter's statement is rather long because he
didn't take an available shortcut (|). For instance the following two are
the same:
model dep = a addvar c a*c addvar*c /link=glogit;
model dep = a|c addvar|c /link=glogit;
I think the latter seems simple enough to write out in a line. It would have
been better if the model statement understood a naturally briefer notation,
model dep = (a addvar)|c;
but this does not seem to work.
If there were many control variables, then I would have made a macro
variable at the top like:
%let ctrl = ca cb cc cd ce cf;
and then reference it in the model statements like:
model dep = a|c addvar1|c &ctrl;
model dep = a|c addvar2|c &ctrl;
In the place of title3, Peter could have labeled each model like:
addvar1: model dep = &ctrl a|c advar1|c;
addvar2: model dep = &ctrl a|c advar2|c;
and the output would have been fine without the title3.
The point is that macro's shouldn't be the first choice solution since --
let's be honest -- the mixture of macro and sas code are much more difficult
to read and write than sas code alone. A common sense advice would be: If
you are going to use a proc, then learn about it first -- before you attempt
to "fix" it with macros.
>> /* run the basic model with a different addvar one at a time */
>> title1 "All babies";
>> title2 "basic model: tall = age|weight";
>> ods html;
>> ods graphics on;
>>
>> %macro basicPlusAddvar(addvar, units=-sd sd);
>> title3 "plus &addvar|weight";
>> proc logistic data=class descending;
>> model tall = age|weight &addvar|weight /link = glogit;
>> units/default = &units;
>> oddsratio age;
>> oddsratio weight;
>> oddsratio &addvar;
>> run;
>> title3;
>> %mend basicPlusAddvar;
>>
>> %basicPlusAddvar(a)
>> %basicPlusAddvar(b)
>> %basicPlusAddvar(c)
>> %basicPlusAddvar(c, units=-2*sd -sd sd 2*sd)
>>
>> ods graphics off;
>> ods html close;
>> title;
>
>***I would rate this as a good improvement. On macro style we are in
>agreement.
>On the other hand, how much of Peter's programming time do you
>estimate the
>the development (in this style) would have saved or cost Peter?
Thanks! In terms of cost -- come on -- I rather think this is very cheap to
write and saves a lot of coding. It has no macro statements at all except
%macro and %mend! Hardly no other kinds of macros are easier to write than
this.
>> %macro basicPlusAddvar(addvar, units=-sd sd);
>> title3 "plus &addvar|weight";
>> proc logistic data=class descending;
>> model tall = age|weight &addvar|weight /link = glogit;
>> units/default = &units;
>> oddsratio age;
>> oddsratio weight;
>> oddsratio &addvar;
>> run;
>> title3;
>> %mend basicPlusAddvar;
And, I think this macro makes the code quite clean and easy to read, mainly
because the parts that don't change are abstracted out to a simple (macro)
name, and the parts that change are explicitly shown as parameters. You can
see right away what stays the same and what not.
%basicPlusAddvar(a)
%basicPlusAddvar(b)
%basicPlusAddvar(c)
if you want to, then you can write it as:
%basicPlusAddvar(addvar=a)
but it just repeats the word "addvar".
If the above looks like a wallpaper-y, then I guess one can write another
macro for looping, like:
%basicPlusAddvars(a b c)
But a cleaner way to do this is to use a utility macro specialized for
looping along a list of items. Say we have such a macro, say, doOver, then
we can possibly write something like:
%doOver(a b c, exec=%nrstr(
%basicPlusAddvar(&_elem_)
))
Now the-still-open question is whether sas macro is a robust enough language
to write this kind of high-level utility macros. I use the term "high-level"
because this macro takes other macro code as a parameter.
Initially I thought sas macro was robust enough, but currently I am not
sure. Someone may have different options about this.
In any case, a general utility macros like %doOver() is quite a different
animal all together and should be written with much more general usage in
mind and with a more robust implementation.
I haven't seen enough macro code Peter wrote, so I cannot estimate how long
it will take him to write something like this. On the other hand, I know of
at least two macros already published that can do something similar, so it
may cost him little to download and start using one. If he can trust that
the utility macros are trustworthy, that is. :-)
Cheers,
Chang
|