• R语言
  • 请教:怎样把SAS中用array写的data set转换成R中的loop 语句?

本人以前用SAS较多,以后老板不想花钱了只好往R转。

以下是用SAS写的一个数据生成的Code,现在要转成R的,试了半天不成,特到此地求高手指点。谢谢了!

SAS

data slcrp0;

set n.slcrp0;/*poor sleep*/

pslp0=0;

array pp{8}slq080 slq090 slq100 slq110 slq120 slq130 slq150 slq160;

do m=1 to 8;

if pp{m}=4 then pslp0=1;

if pslp0=1 then leave;

end;

output;

drop m;

run;

R code

slcrp=read.table('G:\\....data.txt', header=T, sep="\t", na="")

names(slcrp)

str(slcrp)

attach(slcrp)

pslp<-c('SLQ080', 'SLQ090', 'SLQ100', 'SLQ110', 'SLQ120', 'SLQ130', 'SLQ150', 'SLQ160')

n<-length(pslp)

for (i in 1:n)

{if slcrp$pslp==4 {slcrp$pslp0<-1} else {slcrp$pslp0<-0} if slcrp$pslp0==1 break}


<br />
slcrp$pslp0 <- apply(slcrp[pslp] == 4, 1, max)<br />


是酱紫的意思么?
</p>

好象成功了哎!!太感谢了!

R中避免使用显示loop,向量化编程的经典例子。绝对是个好坑,前排占座。

回复 第2楼 的 波波头一头:

看来真是高手在此啊!

还有一问题,在SAS中,我用proc gam来做曲线拟合,在R中也有,SAS中有一个选项是直线加曲线additive 选项for plot,而且直线和曲线的估计都有,R中好象出来只有曲线拟合的图,我把曲线拟合的变量再加到线性变量中,估计值就明显是错的了,

SAS code

ods graphics on;

ods html

gpath="c:\data\image"

style=journal;

proc gam data=slcrp8 plots=components( additive clm unpack);

model crp=spline(age) param(bmxbmi);

title "crp&age";

title "";

run;

ods graphics off;

R code1

CRP.AGE.T<-gam(crp~s(age,bs="cr",fx=TRUE,k=6)+BMXBMI,na.action=na.omit,data=VD)

plot(CRP.AGE.T,,ylim=c(-1.75,1.75), cex.axis=1.35,cex.lab=1.45,mgp=c(2.5,0.75,0),

xlab="Age (yrs)",ylab="Log hS_CRP (mg/dL)",main="")

summary(CRP.AGE.T)

R code2

CRP.AGE.T0<-gam(crp~s(age,bs="cr",fx=TRUE,k=6)+age+BMXBMI,na.action=na.omit,data=VD)

plot(CRP.AGE.T0,,ylim=c(-1.75,1.75), cex.axis=1.35,cex.lab=1.45,mgp=c(2.5,0.75,0),

xlab="Age (yrs)",ylab="Log hS_CRP (mg/dL)",main="")

summary(CRP.AGE.T0)

光良说了,apply()都是骗银的。回头请肖楠配个图。

去年暑假有一天我在ATT实验室吃午饭,就听旁边一群阿三哥在那儿滔滔不绝讨论各种语言,其中一位说到R语言时激动地重复了好几遍“[R is slow] but if you use apply(), it will be really really fast”,我当时心想S语言的作者就在你们10米开外,要是听到这心都会凉了。

apply()是纯R循环,靠它简化代码可以,提速是无望的。这个例子里对行求和会快很多:

slcrp$pslp0 <- as.integer(rowSums(slcrp[pslp] == 4) > 0)
</p>

前方测速区:

> x=matrix(rpois(1e6,5),ncol=10)<br />
> system.time(apply(x==4, 1, max))<br />
   user  system elapsed<br />
  0.396   0.000   0.399<br />
> system.time(as.integer(rowSums(x==4) > 0))<br />
   user  system elapsed<br />
  0.012   0.000   0.012 
</p>

回复 第9楼 的 谢益辉:

这非得配四个图不可啊!

某天,当我发现了叉叉ply 。。。

帅气地重写替换了所有显式循环!

然后有人告诉我其实这些都是骗纸 。。。

我 。。。

回复 第10楼 的 肖楠:深刻……

回复 第10楼 的 肖楠:配图太犀利啦哈哈[s:11]

前来瞻仰图神,手机流量已经阵亡。说起来,果然人脑一小步电脑一大步啊!

回复 第9楼 的 谢益辉:不是完全同意你的观点。*apply()函数在提高速度上完全取决于你所应用的那个函数,你的例子由于max函数本来就是一个遍历的算法,不论如何apply,其计算复杂度随着维度的增加是线性。而大量底层的由C或者其他语言写成的函数apply是很有优势的。

而且*apply()类型的函数的优点不仅仅在于其简洁,而且在于可移植性,如果你的代码写成*apply可接受的形式,则非常方便的移植到并行计算里,比如lapply()->parLapply(),mapply()->clusterMap()。这里得到的性能的提升就相当可观了。

回复 第14楼 的 Feng Li:

后面所说的好处也不完全是 apply 所独有吧,foreach + doMC 也能很方便地迁移 for 做并行。而 **ply 虽然表面简洁但有时不直观,修改处理方式的思考时间,后期维护的时间都是隐形的。

回复 第15楼 的 肖楠:

如果我记得没错的话,你说的迁移是单核到多核的迁移(在一个共享内存的物理CPU内),如果单核到多节点(多核多CPU不共享内存)的迁移,把单个独立的任务写成函数然后应用到各个节点,对我来说foreach+doMC和MPI这些东西绞在一起就是epic fail。

我的经验反而觉得apply函数比写个大loop要好维护很多。因为每次写函数只需考虑的问题一个单一维度。

回复 第2楼 的 波波头一头:

我还是不太放心,在slcrp[pslp]中,是逢4跳出,但是4并不是它的最大值,

而slcrp$pslp0 <- apply(slcrp[pslp] == 4, 1, max)能真正给出与SAS一样的结果吗?

谢谢!

回复 第17楼 的 roena:应该是准确的。另外可以参考第九楼呀。

回复 第16楼 的 Feng Li:

嗯,如果不是一台大机器的话,parLapply 的方式确实优越一些。我看到的一些廉价多机并行可能用 Hadoop 系的 MapReduce 方式更多一些,虽说 MPI 也相当不错。

很少写大 loop, 因为不好控制,更喜欢一步只做一件事,所以其实是没什么区别的。只是对于像我这样不明真相的群众,在循环更自然时,转换到 apply 的角度去写会比较别扭。其实只要不太难写,还都是 apply 直接解决。

相当多的情况下 apply 是能提升一定速度的,不过具体提升多少仍然需要看具体情境。像 9 楼提到三哥说的 "really really fast" 就是过度夸张了 。。。矫枉过正而已。

回复 第14楼 的 Feng Li:我同意你的不同意,你说的也正是我在主站下面评论的观点,这个帖子里我有点邪恶地故意挖坑。等下次有人写一坨难看的循环时再请肖楠重新配图转向apply()……