Categories
日常应用

七彩琴键图...(via ggplot2)

这个纯属做出来卖萌的...只是画出来有高有低比较像琴键的感觉,又按照类别填了一下颜色,所以再卖弄一下来个好听的名字——七彩琴键图。

Year over Year Growth
点击看大图

数据比较敏感,所以很多信息都删掉了...大概还是可以看出来横轴是时间,纵轴是增长率。增长率大于阈值40%则100%上色,否则设为半透明。颜色是ggplot2自己上的,还是挺美观的...从上而下,各个类别的表现比较容易直接区分,这也就是这张图的目的。此外标注了一些重要日期。

可能一般画增长率都会画折线图吧,我只是觉得同样的数据折线图画出来大起大落的太丑了,还是这样好看一些...

最后按惯例,放上代码。其实很短...

library(ggplot2)
require(scales)

# growth
ggplot(q4_yoy, aes(x=DT12, y=ll, color=NULL))+
geom_bar(stat = "identity",aes(fill=Vertical,alpha=ll>0.4))+ #柱状图,然后判断是否大于40%
scale_y_continuous(labels = percent_format())+ #纵轴改成百分比
facet_grid(Vertical~.)+ #分类别画出来
geom_hline(yintercept=0.4,alpha=0.9,color="grey",linetype="dotdash")+ #40%增长率的水平线
geom_vline(xintercept=as.numeric(as.Date("2012-10-31")),
alpha=0.5,color="red",linetype="dotdash")+ #一些重要的日期
geom_vline(xintercept=as.numeric(as.Date("2012-11-22")),
alpha=0.5,color="red",linetype="dotdash")+
geom_vline(xintercept=as.numeric(as.Date("2012-12-25")),
alpha=0.5,color="red",linetype="dotdash")+
geom_vline(xintercept=as.numeric(as.Date("2012-09-22")),
alpha=0.5,color="blue",alpha=0.5)+
#   annotate("text",label="Sep 22",x=as.Date("2012-09-22"),y=-0.5)+
theme_bw()#黑白底板

 

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
读书有感

「Data Manipulation with R」若干笔记

最近两天读R的手册效率奇高无比,果然是和跟taiyun说起的一样,“有需求便有动力”。昨天一上午看完了ggplot2的手册,虽然有些晦涩难懂,但是还是很好的体系理解。p.s. ggplot2新手推荐「Cook Book for R」,先用起来再慢慢回头看原理嘛。ggplot2也是延年益寿的利器,嗯...默认的图都看起来好专业,嘻嘻。

回到本文的正题。看完了ggplot2之后,下一本被我扫荡的手册就是「Data Manipulation with R」,基本的数据整理操作。虽说数据整理是一件很没有技术含量只是耗时间的事情,但是正因如此节省起来时间也是大把大把的,顿时觉得人生加速运行了好多。说来惭愧,用R也有些年头了,一直没有静下心来好好的研究基本的R数据操作方式,总是遇到问题才会亡羊补牢似的上网开始搜,好在现在stackoverflow.com这些网站累积了大量类似的问题,所以搜起来也算方便。但终究不是个长久之计,当忍者太久了总觉得还是应该老老实实的学习一下王道正术。于是,开始花些时间细细的研读起在R里面收拾数据的那九九八十一招。

简单记录一些以前忽略的函数之类的。很多来自神奇的plyr包,如果直接?调不出来帮助那就先加载这个包吧。

  • expand.grid() : 最开始用R的时候,数据都是教材里面给的,整理的规范的很,基本就是调用一个lm()之类的函数扔进去就可以了,所以习惯于直接用factor类型相乘。后来发现经常要建立一些factor相乘出来的矩阵/data.frame之类的东西,却一直不知道怎么办。终于找到了这个函数,嘻嘻。哎,我是有多么懒才一直没有去搜这个需求啊。
  • cut():yihui兄前阵子提到的非常elegent的函数之一(另一个是with(),哎我居然连这个都一直没注意过),基本就是把连续变量离散化,即numeric型的数据转换成factor型的万能钥匙。
  • which():可能以前也没大用到类似的需求,所以没注意。一般来说,对于逻辑型的数据(很多数据筛选问题最后都可以归为逻辑型数据问题),只是选择出来符合条件的元素还是比较容易的,所以一直没留意这个函数。简而言之,就是这个函数返回的不是符合条件的元素的值,而是他们的位置(比如在一个vector中的位置,即下标)。这样有时候还是比较方便的~
  • with():这个就不多说了,基本拯救了需要attach(), detach()的地方,不用常年打dataframe的名称了。p.s. 不知道是什么缘故,很多R的教程上会用attach/detach,但实际中其实很不建议使用啊,容易把object搞混的。
  • arrange():当你需要对一个data.frame进行按照多列依次排序的时候,就不需要依次order了。说来有趣,它的函数帮助里面简洁明了,“This saves a lot of typing!”,可以少打字的都是好东西,嗯嗯。
  • cat():其实也用到过,只是很多时候更习惯paste(),毕竟不是所有的时候都要直接输出。不过需要的时候,还是比print()加paste()方便一些吧。看思考习惯了。
  • substring():常年只会用substr(),其实这两个函数蛮像的,只是参数不同。部分情况下substring()会更方便一些,不过反正有length(), nchar()这种东西,其实问题不大。
  • aggregate(), cast():前几天gaotao回复的时候提到的函数,其实某种程度上我现在更喜欢data.table()了...
  • apply类:sapply(), apply(), lapply(), mapply(),基本就是消灭显式循环的利器(当然消灭循环不仅仅是美观目的,还是提高效率的不二法宝,后面更是各种并行处理的基本架构函数,比如RHadoop重写的那堆函数)。当然,其实有的时候我会更倾向于把显式循环写出来(如果循环量不大比如<10而且每一次循环都还挺快的话)。这么做虽然效率上牺牲了一点,但是提高了代码可读性啊,就不用写很多注释提醒自己为什么当时这么弄了。由此可见我的编程水平基本停留在翻译脑子里面的逻辑化思维过程的模式,并没有实质性的在程序本身架构的角度来思考编程逻辑。咳咳,人家是做分析的,不是码农,效率的问题交给专业人士去解决吧,我更喜欢专注于思考分析的逻辑(多么苍白无力的狡辩,从来不肯在编程上原理上多花功夫的孩子飘过)。

暂时就是这些,最喜欢的就是R这种无限的可能性,总有人会贴心的帮你写好很多函数,然后傻傻的打一个?,看看函数怎么调用怎么附上参数就可以了。这才是美好的人生嘛,不喜欢过多关注那些脏活累活背后的原理,计算机自己辛苦去好了(当然还有那些辛勤的R包开发者们,嘻嘻,谢过大家的努力劳动)。不是有句话么,「科技都是为懒人服务的」。越来越赞同taiyun这次在北京R会上的惊人之语——省时间就是延年益寿。