结合豆瓣基础API学习XML包

很久以前在R-Forge上注册过一个RDouban项目, 想用豆瓣提供的API做点好玩的事情. 可惜后来只写了个开头, 感兴趣的童鞋可以无条件认领. 在这里结合豆瓣的基础API, 非常简略地写一下用XML包读数据的基本问题.

1 XPath

花十分钟学习XPath语法.
熟练后可使用Firebug等调试工具直接提取. 此外, 要特别注意XML命名空间问题. (感谢yixuan提醒)

2 Douban API

花n分钟阅读"豆瓣API参考手册".
用户的评论、收藏、广播、豆邮等交互功能往往需要先进行OAuth认证, 建议阅读RFC5849以充分理解OAuth协议. 这块目前也有ROAuth包可以实现, 不过与读数据没什么关系, 此略.

继续阅读

使用Google Perftools和kcachegrind深入剖析R程序性能瓶颈

“颐和园在我家北面,假如没有北这个方向的话,我就只好向南走,越过南极和北极,行程四万余公里到达那里。”

——《革命时期的爱情》

1 剖析与Profiling

这里的"剖析"对应的单词是"profiling", 中文似乎没有词语能精准地表达出原词的内涵, 与"shell"的情况有点类似, 所以就不去刻意翻译了. 由于没有学过软件工程, 不吝先贴一段wiki上profiling的定义[1]:

In software engineering, program profiling, software profiling or simply profiling, a form of dynamic program analysis (as opposed to static code analysis), is the investigation of a program's behavior using information gathered as the program executes. The usual purpose of this analysis is to determine which sections of a program to optimize - to increase its overall speed, decrease its memory requirement or sometimes both.

要提高R程序的运行速度, 不仅仅需要剽悍的机器(单核高频, 多核并行, GPU)和高效的代码(向量化, 混合编程), 寻找程序中的性能瓶颈并进行有针对的优化也是很重要的, "找到北这个方向", 就是profiling的意义所在.

R中其实自带了几个最简单的profiling工具, 我们或多或少都接触过:

  • base::system.time() —— 简陋的计时秒表
  • utils::Rprof() —— 对CPU的简易profile工具
  • utils::Rprofmem() —— 对内存的简易profile工具

关于这些函数的使用, 可以参看Ross Ihaka的说明[2]. 与此同时, CRAN上profr(Hadley Wickham)和proftools(Luke Tierney)两个微型包均提供了可视化Rprof()函数输出结果的能力. 但是, 这类简单的profiling只将程序拆解了到了单个R运算的层次, 没有提供更深一层, 即profiling compiled code的功能. R原生支持这个特性, 但需要在编译时对默认选项进行简单的修改[4].

2 安装Google Perftools

翻看Dirk Eddelbuettel牛在useR2010上的RhpcTutorial[3], 其中提到了Google员工开发的Google Perftools可以profiling compiled code. 试了一下, 感觉是个不错的工具, 配合kcachegrind, 还可以将结果可视化.

测试环境: Arch Linux x86_64

AUR上已有一位大人在维护google-perftools(源代码安装):

sudo yaourt -S google-perftools

Fedora:

sudo yum install google-perftools

Ubuntu:

sudo apt-get install google-perftools

不过Ubuntu/Fedora仓库中的二进制包可能比较陈旧了, 无妨直接自行编译最新版本:

svn checkout http://google-perftools.googlecode.com/svn/trunk/

在Arch x86_64下, google-perftools的默认安装路径为

/usr/bin

库文件libprofiler.so位于

/usr/lib

Google Perftools工具集中除了名为pprof的CPU profiler以外, 还提供了堆内存泄漏检测/使用情况统计等工具. 这里我们只关注pprof就可以了: 它通过CPU中断采样的方式统计每个函数被采样的次数, 占总采样次数的百分比, 调用的子函数的被采样次数等等(可以说"剖析"在此处还是比较恰当的). 最后通过这些信息寻找程序的(CPU)性能瓶颈.

3 使用Google Perftools

要和R一起使用, pprof有两种可行的运行方式, 第一种比较硬朗: 在编译选项中直接加入对libprofiler.so的引用, R在运行时就会自动加载libprofiler库:

wget http://cran.r-project.org/src/base/R-2/R-2.13.1.tar.gz
tar -xf R-2.13.1.tar.gz
cd R-2.13.1
 
export MAIN_CFLAGS="-pg"
export MAIN_FFLAGS="-pg"
export MAIN_LDFLAGS="-pg"
export LDFLAGS="-lprofiler"
# 也可显式指定路径:
# export LDFLAGS="-L/usr/lib -lprofiler"
./configure --enable-R-shlib

参数 -pg 打开R的profiling支持, 设定LDFLAGS用以连接libprofiler库.

configure完成:

R is now configured for x86_64-unknown-linux-gnu

  Source directory:          .
  Installation directory:    /usr/local

  C compiler:                gcc -std=gnu99  -g -O2
  Fortran 77 compiler:       gfortran  -g -O2

  C++ compiler:              g++  -g -O2
  Fortran 90/95 compiler:    gfortran -g -O2
  Obj-C compiler:	      

  Interfaces supported:      X11
  External libraries:        readline, ICU, lzma
  Additional capabilities:   PNG, JPEG, TIFF, NLS, cairo
  Options enabled:           shared R library, shared BLAS, R profiling, Java

  Recommended packages:      yes

结果无误, 开始编译安装:

make && sudo make install

这样, 连接了libprofiler.so的R编译成功.

第二种使用pprof的方式则相对委婉: 使用时动态预加载库文件就可以了, Dirk大人的RhpcTutorial中已经给出说明, 此略.

选取《Wringting R Extension》 3.2节中给出的一个例子进行测试:

?Download profiling.R
#!/usr/local/lib64/R/bin/Rscript
suppressMessages(library(MASS))
suppressMessages(library(boot))
storm.fm <- nls(Time ~ b*Viscosity/(Wt - c), stormer, 
                start = c(b=29.401, c=2.2183))
st <- cbind(stormer, fit=fitted(storm.fm))
storm.bf <- function(rs, i) {
    st$Time <-  st$fit + rs[i]
    tmp <- nls(Time ~ (b * Viscosity)/(Wt - c), st, start = coef(storm.fm))
    tmp$m$getAllPars()
}
rs <- scale(resid(storm.fm), scale = FALSE)
storm.boot <- boot(rs, storm.bf, R = 500)

将profiling结果记录到文件:

chmod 755 profiling.R
CPUPROFILE=rprof.out ./profiling.R

这里在写R文件时用了一点点技巧, 使得它能够支持类Unix系统的Shebang特性而直接执行, 参考[7], [8].

执行完毕后, 我们即可使用pprof来分析输出的结果文件(一个二进制文件!)了. pprof可以将此文件解析成你想要的各种可读的形式. 其参数如下:

pprof --option [ --focus=< regexp > ] [ --ignore=< regexp > ]
                      [--line or addresses or functions] 可执行文件路径 结果文件路径

方括号为可选项目, < regexp >为正则表达式.

具体的选项分为几组. 其中输出格式的基本可选项为:

text, callgrind, gv, evince, web, symbols, dot, ps, pdf, svg, gif, raw, list=< regexp >, disasm=< regexp >.

text 表示字符统计输出形式, 其它均对应各自的图形格式;
list=< regexp > 表示输出匹配正则表达式的函数的源代码;
diasm=< regexp > 表示输出匹配正则表达式的函数的反汇编代码.

其他比较重要的参数:

--focus=< regexp > 表示只统计函数名匹配正则表达式的函数的采样;
--ignore=< regexp > 表示不统计函数名匹配正则表达式的函数的采样;
[--line or addresses or functions] 表示生成的统计是基于代码行, 指令地址还是函数的, 默认是函数.

这里仅输出文字型结果:

pprof --cum --text /usr/local/lib64/R/bin/Rscript rprof.out | less

结果中的前15位:

Total: 254 samples
       2   0.8%   0.8%      213  83.9% Rf_applyClosure
      24   9.4%  10.2%      213  83.9% Rf_eval
       0   0.0%  10.2%      213  83.9% do_begin
       0   0.0%  10.2%      212  83.5% do_set
       0   0.0%  10.2%      206  81.1% do_internal
       0   0.0%  10.2%      148  58.3% do_lapply
       7   2.8%  13.0%      123  48.4% Rf_evalList
       0   0.0%  13.0%      107  42.1% Rf_ReplIteration
       0   0.0%  13.0%      104  40.9% R_ReplConsole
       0   0.0%  13.0%      102  40.2% Rf_usemethod
       0   0.0%  13.0%      100  39.4% run_Rmainloop
       0   0.0%  13.0%       96  37.8% main
       0   0.0%  13.0%       92  36.2% __libc_start_main
       0   0.0%  13.0%       85  33.5% do_usemethod
       1   0.4%  13.4%       85  33.5% forcePromise

输出结果中, 每行对应着一个函数的统计:

  • 第1, 2列是该函数的本地采样(不包括被该函数调用的函数中的采样次数)次数和比例;
  • 第3列是该函数本地采样次数占当前所有已统计函数的采样次数之和的比例;
  • 第4, 5列是该函数的累计采样次数(包括其调用的函数中的采样次数)和比例.

如果你的系统中安装了gnu-gv或evince, 即可直接即刻显示一幅无码清晰大图(ps/pdf):

pprof --gv /usr/local/lib64/R/bin/Rscript rprof.out
pprof --evince /usr/local/lib64/R/bin/Rscript rprof.out

rprof

其他几个比较常用的选项可能是

生成PDF:

pprof --pdf /usr/local/lib64/R/bin/Rscript rprof.out > rprof.pdf

生成SVG:

pprof --svg /usr/local/lib64/R/bin/Rscript rprof.out > rprof.svg

生成GraphViz所支持的dot格式:

pprof --dot /usr/local/lib64/R/bin/Rscript rprof.out > rprof.dot

当然, 要想读懂图中的内容, 从而针对某些部分进行优化, 还需要对R的底层比较熟悉才行: 最起码要了解涉及到的C函数的具体功能.

4 配合kcachegrind可视化profile结果

pprof可将输出转化为强大的Valgrind工具集中的组件Callgrind可采用的格式, 配合KCachegrind这个图形前端, 即可对结果进行简单的可视化, 能够交互哦亲:

# For Arch Linux
# sudo pacman -S kdesdk-kcachegrind
pprof --callgrind /usr/local/lib64/R/bin/Rscript rprof.out > rprof.callgrind
kcachegrind rprof.callgrind

kcachegrind

其实看上去KCachegrid就是做了一个最普通的树可视化, 所以理论上我们其实可以用角度各异的无数种手段展示profiling结果: 就是画一棵树嘛. 不过KCachegrind中可以与图形交互, 进一步的分析很方便, 大家可以自己进一步体验.

5 其他工具(sprof和oprofile)

Writing R Extensions[6]提到另外两个可供Linuxer选择的工具: sprof和oprofile, 我没有实验, 感兴趣的同学不妨实践一下.

6 参考

[1] Wikipedia - Profiling (computer programming).
[2] Ross Ihaka. Writing Efficient Programs in R (and Beyond).
[3] Dirk Eddelbuettel. Introduction to High-Performance Computing with R. pp. 29-35
[4] R Installation and Administration. Version 2.13.0 (2011-04-13) Appendix B.1, B.7.
[5] 冯文龙. 使用google-perftools剖析程序性能瓶颈.
[6] Writing R Extensions. Version 2.13.0 (2011-04-13) pp. 69-71.
[7] Wikipedia - Shebang.
[8] shebang line not working in R script.

小径分岔的花园

前天晚上发出一篇质量平平的博文后, 太云学长提出一个建议(其实算是中肯的批评): 用点的大小表示震级的大小. 其实以前也不是没想过这个问题. 只是不怎么懂R中的向量操作, 加上自己比较懒, 所以就 ... 昨天没去教室学习(极度堕落啊), 正好宅在寝室里没事, 就画出来玩玩.

我们首先绘制图1, 点的半径大小代表震级的高低. 点的半径越大, 震级越高. (数据附文后)

图1 震级的大小

图1 震级的大小

然后绘制图2, 点的透明度高低代表震源的深度, 点的透明度越靠近完全不透明 (完全不透明的红色为#FF0000FF), 表示震源深度越浅.

图2 震源的深度

图2 震源的深度

继续阅读

R环境安全特性初探与前瞻,这次R语言会议的slides

汗啊,过了1个多月才放上来,从会场赶回学校以后一忙就把这事儿忘到九霄云外了,假期都到家了才想起来,真是对不住大伙了 ..

其实之前在COS主站上有发,只是那个版本稍旧,是在北京会场时使用的,此版本为上海会场使用的最终版,有一些增补和删改。没有太云学长陈丽云学姐他们用Beamer精心制作的slides那么优雅飘逸,俺用Office 2010 Beta做的,不知字够不够大,希望大家能看清楚吧。

R环境安全特性初探与前瞻 (PDF, 2.95MB)

此文档遵循CC3.0,不过这里要特殊说明一下:

此文档仅为单纯的技术分析,任何个人或机构根据本文内容实施的任何行为,以及带来的任何经济损失、法律争议和相关后果,作者概不承担任何责任。

至于对应的paper,其实在去年11月份的时候就“凑”得差不多了,在这里偷个懒,就不发了。

感谢大家的关注和支持,小弟在此谢过。

第二届中国R语言会议 Dec 12-13, 2009 @ ECNU

shanghai_subway_1

写完才发现自己原来用了纯粹的倒叙。

关于记录,请看这位学姐的博文。已经写得很好了。

唯一的遗憾是这次没能和贝吉塔道别。劝君更尽一杯酒,天下谁人不识君(姊妹篇是这句:垂死病中惊坐起,笑问客从何处来)。

03
继续阅读

第二届R语言中文会议 @ RUC 第二天趣事及补记

美好的时光总是短暂的。这两天总是无意中回想起两天前会议的情景,又看到了太云学长写了通宵的博文,我总觉得要再说点什么。太云学长全面的总结了自己对所有演讲和演讲者的感受,我就从另外的角度简单的补充一点吧。

先说说相当nice的Yanlinlin哥哥,我想说的是,Thank you so much .. 其实Yanlinlin哥哥一眼就看出了我所说问题的核心,并且给了我很好的建议,还与我分享了一些工作中的心得 ..(保持常年开机啊 :-) ,俺还要常常关注你架在自己机器上的blog) 。在上午报告的空闲中,认识了来自BNU的王化儒学长,暑假那次很不成熟的“审稿”时就曾经拜读过学长在第一届会议时的作品,这次见到“真人版”,学长带给我的感觉是一个朴实而有内涵的大男孩 .. 和我想像中的差不多..
第二天中午用毕午餐后(感谢RUC的会议组织者们,两天的午餐都很丰盛 .. 你们如此的体贴周到 ..再次感动),在bjt的带领下,我和Yanlinlin哥哥、从上海赶来的George Zhang还有牟先生一起小逛了下人大校园,我觉得人大校园的每一个角落似乎都有着bjt的故事和回忆,赞一下名校的校园文化 .. 一个小插曲,George Zhang向我们传授了高端的摄影理论,那就是 —— 都甭看镜头啊! 于是,预计中几张杰作诞生了 .. 不知范兄是否搜集到了,这里悄悄给出Zhang的摄影博客 低调路过下 .. 我觉得黑白影像的部分尤其好,很有feel ..

继续阅读