Date: Sun, 8 Jul 2012 22:52:22 -0600
Reply-To: Fried Egg <friedegg2012@GMAIL.COM>
Sender: "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From: Fried Egg <friedegg2012@GMAIL.COM>
Subject: Re: Understanding environment where run_macro executes
In-Reply-To: <201207082356.q688xlQa005345@waikiki.cc.uga.edu>
Content-Type: text/plain; charset=ISO-8859-1
I spent less than 30 minutes on this, but it works for your example. The
basic concept is to build a R script file and execute it in batch mode in
R. The SAS7BDAT package for R doesn't work on my machine so I just use xpt
files in both directions. If no additional processing on the data being
retrieved from R is necessary then the set statement is unnecessary and the
datastep would just need to be a null. I think it would be interesting to
build a client side adapter to Rserve for SAS Foundation. Overall I still
think there is little point to reinventing the wheel when it already exists
with SAS/IML.
%macro xportsds;
libname xpt xport "%sysfunc(dequote(&path))";
proc copy in=%sysfunc(dequote(&libref)) out=xpt;
select %sysfunc(dequote(&sds));
run;
libname xpt clear;
%mend;
%macro xportxpt;
libname xpt xport "%sysfunc(dequote(&xpt))";
proc copy in=xpt out=%sysfunc(dequote(&olib)) memtype=data; run;
libname xpt clear;
%mend;
%macro rxeq;
filename rpgm temp;
data _null_;
file rpgm lrecl=32767;
put "%sysfunc(dequote(&rpgm))";
run;
x /usr/lib64/R/bin/R CMD BATCH %sysfunc(pathname(rpgm,f));
filename rpgm clear;
%mend;
proc fcmp outlib=work.func.rndm;
subroutine xportsds(sds $,libref $,path $);
rc=run_macro('xportsds',sds,libref,path);
endsub;
subroutine xportxpt(xpt $,olib $);
rc=run_macro('xportxpt',xpt,olib);
endsub;
subroutine rxeq(rpgm $);
rc=run_macro('rxeq',rpgm);
endsub;
run;
options cmplib=work.func;
data linreg2;
call xportsds('class','sashelp','/home/sas/class.xpt');
call rxeq(compbl(
'library(SASxport);
library(Zelig);
library(sqldf);
cls <- read.xport(''/home/sas/class.xpt'');
z.o1 <- zelig( AGE ~ SEX + WEIGHT + HEIGHT
, model = ''aov''
, data = cls );
resid <- z.o1$residuals;
fit <- z.o1$fitted.values;
residual <- cbind( cls , resid , fit );
cof <- data.frame( SexC = z.o1$coefficients[2] ,
WeightC = z.o1$coefficients[3] ,
HeightC = z.o1$coefficients[4] );
linreg <- sqldf(''select l.*
, r.SexC
, r.WeightC
, r.HeightC
from residual as l
, cof as r'');
write.xport(linreg,file=''/home/sas/linreg.xpt'',autogen.formats=FALSE);'
));
call xportxpt('/home/sas/linreg.xpt','work');
do _n_=1 by 1 until(done);
set class(obs=1) linreg open=defer;
if _n_>1 then do;
*do something else;
output;
end;
end;
stop;
run;
On Sun, Jul 8, 2012 at 5:56 PM, Roger DeAngelis
<rogerjdeangelis@gmail.com>wrote:
> Hi Toby,
>
> That was a bogus posting in so many ways. I realized it after I sent it
> but I did't know how to delete it. You are correct about symget in the same
> dataset. Thanks for correcting me. Typically a macro variable with the
> average would only be available after the last observation was processed.
> Here it is right after the set on observation 1. I am a little rusty since
> I
> have been away for a couple of years. It was supposed to be a proof of
> concept but even the concept was wrong. There are many better ways to get
> the deviation with other SAS functionality.
>
> Here is the problem I have been working on, which brings together some of
> the recent posts. This is a proof of concept and I know about R and IML,
> proc reg and sums of squares and deviations from procedures like proc corr.
> I know it would look cleaner in pure SAS. But R has over 3,000 packages.
>
> /* the following R code performs
> proc reg data=sashelp.class coef=cof?;
> model Age = Sex Weight Height;
> output out=linreg residual=resid predicted=fit;
> run
>
> Without SAS STA and inside base SAS datastep.
>
> The dataset returned from R has the following structure.
> sashelp.class plus regression output
>
> # Variable Type Len Label
>
> 1 RESID Num 8 Residual from Regression
> 2 FIT Num 8 Fitted Value
> 3 SEXC Num 8 Coefficient of Sex
> 4 WEIGHTC Num 8 Coefficient of Weight
> 5 HEIGHTC Num 8 Coefficient of Height
> 6 NAME Char 8
> 7 SEX Char 1
> 8 AGE Num 8
> 9 HEIGHT Num 8
> 10 WEIGHT Num 8
>
> If there is interest in the code I will
> gladly send it to anyone who is interested.
> It is to much to paste into this message.
>
> I hope others will find R as useful as I have
>
> */
>
> data linreg (drop=pgm);
>
> length pgm $1024 resid fit sexc weightc heightc 8.;
>
> label
> Resid ="Residual from Regression"
> Fit ="Fitted Value"
> SexC ="Coefficient of Sex"
> WeightC ="Coefficient of Weight"
> HeightC ="Coefficient of Height";
>
> set class(obs=1) r.linreg open=defer;
>
> if _n_=1 then do;
> /* R CODE */
> pgm=compbl("
>
> library(sas7bdat); # read sas7bdat;
> library(SASxport); # create xport dataset;
> library(Zelig); # proc reg;
> library(sqldf); # proc sql;
>
> cls <- read.sas7bdat('c:\\utl\\class.sas7bdat');
> # proc reg;
> z.o1 <- zelig(Age ~ Sex + Weight + Height,
> model = ""aov"", data = cls);
> resid <- z.o1$residuals;
> fit <- z.o1$fitted.values;
> residual <- cbind(cls,resid,fit);
> cof <- data.frame(SexC=z.o1$coefficients[2],
> WeightC=z.o1$coefficients[3],HeightC=z.o1$coefficients[4]);
>
> # sql to join with coeficients;
> linreg <- sqldf('select l.*, r.SexC, r.WeightC,
> r.HeightC from residual as l, cof as r');
> write.xport(linreg,file='C:\\utl\\linreg.xpt',autogen.formats=FALSE);
> ");
> /* EXECUTE R CODE */
> call rxeq(pgm);
> end;
> else output;
>
> run;
>
|