Categories
日常应用

探索R包plyr:脱离R中显式循环

所有R用户接受的第一个“莫名其妙”的原则就是:

不要在R中写显式循环...

不要写显式循环...

不要写循环...

不循环...

不...

我第一次接受到这个“黄金律”,就跟当年从basic语言转到C语言的时候,老师说:

不要写go to...

不go to...

不...

一样的,好震撼。往往对于R用户来说,R基本上不可能是他们学习的第一门计算机语言,什么C啊Java啊甚至matlab或者VBA都可能排在R前面。所以,循环,无论是for还是while,好像都是再家常便饭不过的事情了。换句话说,不准写循环,我要你计算机还辛辛苦苦的码代码干啥?你丫不就是一免费精确的重复劳动力么!

带着一种到处循环的思维,接触R的初期我是各种不适应不适应啊。循环不让写???后来习惯了去搜R的各种稀奇古怪的函数,发现基本上我想用的功能都被其他大牛们实现了,只需要知道怎么调用那些函数和参数就可以了。这个,挺好的嘛,适合我这种懒人。可是,总有一些时刻需要写循环的嘛...呜啊。

后来,lijian哥给我不断的潜移默化各种展示sapply等apply类函数的强大,越来越体会到一种思维习惯的变化——不再是循环,而是向量操作。这就好比以前只知道求和公式的孩子一朝学习了矩阵乘法,各种惊讶膜拜。其实,从这个角度来讲,R里面很多东西都是更希望借助向量来做而不是自己一个一个的写循环。嗯啊,果然思维方式是有很大提升的。

在痛苦的跟apply类函数纠结了一阵子之后,惊讶的在stackoverflow.com上看到许多人用一个莫名其妙的ddply函数或者ldply函数来实现类似sapply的功能,一时之间难免好奇。于是按图索骥,找到了神奇的plyr包。于是,开启了一扇门(顿时想到叶诗文拿到第二枚金牌的时候,两位央视解说员激情四射的即时附和)。相映成趣啊。plyr的解释只有一句:The split-apply-combine strategy for R。嗯,超级符合其作者一贯的风格...

简单来说,这个包就是用来简化apply类函数的使用的。作者给出了一个稳健回归的例子(原文载于JSS):

已有函数:

deseasf <- function(value) rlm(value ~ month - 1)

循环版:

models <- as.list(rep(NA, 24 * 24))
dim(models) <- c(24, 24)
deseas <- array(NA, c(24, 24, 72))
dimnames(deseas) <- dimnames(ozone)
for (i in seq_len(24)) {
for(j in seq_len(24)) {
mod <- deseasf(ozone[i, j, ])
models[[i, j]] <- mod
deseas[i, j, ] <- resid(mod)
}
}


非循环版:

models <- apply(ozone, 1:2, deseasf)
resids_list <- lapply(models, resid)
resids <- unlist(resids_list)
dim(resids) <- c(72, 24, 24)
deseas <- aperm(resids, c(2, 3, 1))
dimnames(deseas) <- dimnames(ozone)

plyr版

models <- dlply(ozonedf, .(lat, long), deseasf_df)
deseas <- ldply(models, resid)

嗯,代码长度上可以看出来显著差别了吧,嘻嘻。基本上,plyr就是一步步的从split()到lapply()最后rbind()结果嗯。我个人是怎么用的呢?小小剧透一下,最近在处理一堆XML数据,虽然自认对HTML很熟,但是对XML还是各种两眼一抹黑。为了把XML转为方便的data.frame格式,网上一通乱搜最终找到了简洁的解决方案:

## xml_names中含有一系列的XML文件地址,为字符串向量。
xml_df <- ldply(xml_names,
function(x) {
as.data.frame(t(xmlToList(x)$weibo_fans))
}
)

调用XML包的xmlToList()函数之后,就可以用ldply方便的开始揉数据了。嘻嘻,然后加一个 print()函数,就可以舒舒服服的见证屏幕上几千个XML文件被慢慢刷成自己想要的格式的过程了。爽死了。

从数据输入上来看,支持三大类——array,list和dataframe。我个人最偏爱dataframe,虽然list有时候更方便灵活。另外还有几个方便的函数可以用,比如:

  • each():each(min, max)等价于function(x) c(min = min(x), max = max(x))。
  • colwise():colwise(median)将计算列的中位数。
  • arrange():超级顺手的函数,可以方便的给dataframe排序。
  • rename():又是一个handy的函数,按变量名而不是变量位置重命名。
  • count():返回unique值,等价于length(unique(**))。
  • match_df():方便的配合count()等,选出符合条件的行,有点像merge(...,all=F)的感觉。
  • join():对于习惯SQL的童鞋,可能比merge()用起来更顺手吧(当然也更快一点),不过灵活性还是比不上merge()嗯。

好吧,看出这位作者Hadley的风格了吧,基本上能save your life的函数都给预备好了。现在我的办公桌上常年挂着stringr的简短说明,然后习惯ggplot2画图,reshape2揉数据...这算不算Hadley依赖症捏?

------Happy Hour (欢乐时光模式开启)------

Categories
事儿关经济 网络新发现

[译文]动物们真的有动物精神吗?

原文标题:Do Animals have Animal Spirits? 

Marginal Revolution新鲜出炉的一篇博文。我承认这次我是标题党,动物精神是我比较感兴趣的一个话题而已。

译文:

我们在自然界中很容易看到“真实商业周期(real business cycle)”。我们不妨想象一个小生态系统——池塘。有一年一只寄生虫感染了浮萍。没有浮萍那么青蛙就没法捕捉飞虫,而后飞虫大量繁衍,但是青蛙却倍感饥饿,导致梭子鱼能吃的东西也变少。如果我们衡量总池塘的生物量(gross pond biota,GPD——译者注:这个我开始居然看成GDP了),我们可以看出自然的循环。事实上,如果我们测量池塘中的不同“部门”(青蛙、飞虫等),我们可以描绘出一幅完整的池塘中的每个部门依次对于开始这个冲击的反应、以及对其他所有部门的影响(就如同向量自回归)。

池塘里有一个凯恩斯经济周期吗?换言之,动物精神可以驱动一个自然界的商业循环吗?对我来说,很难确切的看出这个循环怎么工作。我们需要“钱”或者类似的东西对流动性产生冲击并且带来投资的下降。我们或许会得到一个群体协作类型的商业周期(coordination type business cycle with herd behavior,如同Roger Farmer)。有趣的是,在生物学中的这个趋势,至少在我看来,已被认为是群体行为——作为群体的最优选择,但在这里并不一定适用。我们知道粘菌在面对压力时候的自我组织和聚集。这个过程可以没有或者只有很少的外部冲击吗?一个自然生态系统可以提供一个商业周期循环的行为模型吗?如果只有人类拥有动物精神的话,这恐怕有些稍显荒诞。生物学和经济学有很多值得相互借鉴之处(译者注:比如一位评论者就说到“用Google Scholar”搜索一个生态系统循环模型“economics Lotka–Volterra”将得到3000+结果。)

顺带翻译一下的一个貌似来自学生物的人的回复:

如果我们允许青蛙换换口味,吃点原来不爱吃的东西,那么我们将不会看到如上的循环。
如果我们允许青蛙储存飞虫,我们也将看不到这个循环(他们将消耗那些存货并且用来交易)。

---我对生物学的了解胜于宏观经济学,先在此致歉。