有幸参加了今年R语言会议,十年之后,我再一次来到帝都。不愧是北京的大学,人大的建筑一看就很大气!
这次R会盛况空前,演讲那么多,第二天还开了分会场,所以肯定是听不完的,加上我很担心第二天的讲座,所以我只认真听了部分的讲座(罪过罪过)。所以我只选择我印象深刻的内容讲一下。
1. Hadley Wickham : 我居然几乎全部听懂了Hadley说什么!大概因为我也做一点R开发的缘故吧。惭愧的是,听到这个讲座我才知道devtools这个包是他写的,而且我也没有用过。我就是那种用pakage.skeleton()做一个空包然后自己把代码填进去的人。有好用的工具一定要用,往节省人力的资源方向去才是正道啊!最后Hadley还吐槽了一番CRAN,怨念太深了!
2. David Smith : 他一上台先试拍了一张观众的照片,然后以观众为背景自拍了一张,好萌啊!不过他说的内容我没有怎么听懂。
3. 余凯:虽然我最近一直听说Deep learning,但直到现在还没有谁跟我认真地分析过“什么是Deep learning”,看来还是要读论文。
4. 周明:用计算机去做对联和绝句。老实说,我觉得这种思路是错的,但很不好意思,我想不到好的思路。但是我觉得诗词不是选择一个概率大的字词,而是选择一个最好的字词。这种事情,目前人工智能做不到。不过要是计算机能做到帮我完成各种应用文(包括申请书和给那些跟我不熟悉的上级的信件)那该多好!我觉得这个方向才是正路。
5. 王汉生:王老师也是非常萌的一个人,可惜我不做社交网络。统计基础也差,实在没有听懂(请轻揍)
下午是金融专场,这种高富帅领域好像真不适合我(说真的,经济学和金融的东西我真的读不下去,不知道是智商还是兴趣原因,希望是后者吧),不过腾讯工程师说的并行矩阵分解工具真的很厉害,可惜不开源就是了。后来我溜出去找当年睡在我下铺的兄弟福哥。感谢他带领我游览清华,还让我结识了另一个学霸飞哥。他们学电力的往往都是在实验室待到十一二点,实在让老衲惭愧啊!
第二天分了几个专场,所以不可能全部听完。
我先试在A场听。
6. James Wicker : 他做的工作和我师兄的工作有点相同,就是要分辨到底一堆样本中,包含了多少种分布,怎样把这些分布分辨出来。我觉得这个方向还挺有意思的:你可以将很多事情的发生看做很多因素的结果,每个因素对应一个概率分布,要是能把这些概率分辨出来,你就把这些因素理清楚了。当然这个问题很难,而且我还没入门。回头看看论文去。
其他的讲座我基本都忽略了,因为我下午要上台,非常紧张!
7. 任坤:任坤师兄的pipeR真的是一个很有用的包,尤其是像我这种经常要做数据清洗的人来说,这种管道符操作的方式很实用。
8. 邱怡轩:轩哥将SVD,深入浅出。他说的用SVD做矩阵补全,开了我的眼界,准备回头就用这种思路去做一下Kaggle最近的比赛。
总的来说,印象深刻的就是这几场演讲了。第二天分了三个会场,有些很想听的内容时间都冲突了,真是可惜。
R会以外的八卦:
1. 没想到南下和北上的高铁车型是不同的,回广州的车不同于去北京的车,热水间里面没有一次性纸杯,所以只好买了一瓶高铁上的矿泉水。
2. 高铁上冷气比较足,去的时候我是抱着带去换洗的衣服取暖的。回来的时候干脆一发狠,掏出电脑算个比较大的kmeans,让发热的电脑成为我的暖炉(何等码农做派!),回去路上不断看窗外,北方民居和南方民居真的有很大不同啊。那种平原景象很吸引我。
3.路上还看完了英文字幕的《处刑人》。
4.我爸问我,北京比起04年,有什么变化。我说,就只有地铁要安检这个变化,问了其他人,说,也就空气污染更严重了吧。
虽然很难理解为什么有这样的需求,但是我还是遇到过这样的要求:怎么把不同的结果保存到一系列按照某种规则命名的变量中。而且是不止一次遇到这种需求。
我觉得通过合理地安排编程逻辑,应该可以避免,但是无法避免的时候,还是有别的方法的:在R中,实用assign(x, value)语句。这样可以创建一个名为x(注意到x是一个字符串)的变量,并将value对应的值赋予它。
不过今天师妹给我带来了新的挑战(师妹真的是人类进步的动力啊!):如果需要将当前环境中名为a0~a9的变量中的一部分赋值给b0~b9的变量,那么,即使用assign也有一点难度。因为当师妹用如下代码的时候:
for(i in 0:9) { vname <- paste("a", i, sep="") assign(paste("b", i, sep=""), value=vname) }
得到的结果是b1="a1"这样的结果,也就是说,我们把一个字符串赋值给b1了!
我给出的方法是用environment():
vars <- environment() for(i in 0:9) { vname <- paste("a", i, sep="") assign(paste("b", i, sep=""), value=vars[[vname]]) }
嗯,任务完成!准备让师妹请我吃顿饭。
当然,在我敲下上面这句话的时候,我觉得,这种做法挺脑残的。首先这不是一种好的代码风格,然后,其实把a1~a9放在一个列表里面不就结了吗?
不过,还是很开心,因为估计能够坑来一顿饭,而且让我可以写一篇博客。
下午师妹问我,如果在R中一次生成多个随机数,和在一个循环中生成的随机数,会有什么不同?
简单地做个实验:
set.seed(123) runif(3) set.seed(123) for(i in 1:3) { print(runif(1)) }
两个输出的结果是一样的。无论是一次生成多个随机数,还是在一个循环中生成随机数,都是从一个种子出发,生成一个随机序列。如果初始的种子一样,那么生成的随机序列也是一样的。
从这里出发,开始探索一下R中随机数生成的原理。于是去看R中的源代码,在R 中直接输入runif得到的结果是:
> runif function (n, min = 0, max = 1) .External(C_runif, n, min, max) <bytecode: 0x9bd23a4> <environment: namespace:stats>
.External调用C_runif,而C_runif其实是一个指向动态链接库的指针,并不是一个函数的名字(看C_runif没有带有引号可知,关于这一点可以参考stackoverflow上的一个讨论 )。在R的源代码下,可以在src/main/name.c中,找到对应runif的函数:do_random2,还可以看到do_random2对应了多种分布,通过一个偏移量(offset)来区分,接受三个参数。
于是,我们找到了runif的底层源码,至于这个源代码能告诉我们什么,有空再写。