关于在R programming中制止显式轮回的一些要领
这是一篇之前宣布在人人上的旧文了,第一篇分享量破百的原创日志,因此甚是欣慰,窃觉得内容或者另有一些可取之处,而且这篇日志也让我很幸运的结识到了许多R的大牛,许多高程度的评论让我获益匪浅,故搬到本身的新blog上作为一个眷念,顺便做一些批改和更新,原日志和相关评论请点这里,别的在文章最后附上了本文对应内容的pdf文档下载,内容无太多区别,只是语言显得更为正式一点,暂且可以委曲作为一篇文档吧。作此说明之后顿时切入正题。
地球人都知道表明型语言的显式轮回很呵呵,不外传闻最近matlab的轮回又优化过了,貌似挺给力的,但预计恐怕照旧达不到大部门人的需求,由于正亏得programming的时候遇到了这种环境,所以想到了这个常常被人提起的话题,也算是编程的一个tip吧(虽然本文内容编译型语言大神照旧忽略更符合,以免伤了你们的眼睛),别的制止轮回除了具有实际意义之外尚有必然的装逼意义,举个例子当我们读R、matlab可能Gauss之类的代码时,假如看到内里没有一个显式轮回时,总会有一种很牛逼的感受(假如我们以为这是必需的话),并且可读性很是棒,不外要先申明,制止轮回并不等价于加快,坑爹的环境也不少见,不外用于装逼照旧不错的。提前注明本文纯属虚构,如有类似那我必定彩票能中大奖了。文中所有引用均已表白出处,未标明出处即为原创。
这里以计次轮回for为例,请答允我把tips归为四类:1 措施向量化:向量化措施已经是老生常谈的话题了,小我私家感受这是一个既需要智商又需要履历的活,虽然履历大概更重要。因为许多表明型语言都用了blas,这样的话矩阵运算速度是优于C的,更利便的在于往往一句话就能抵掉C中的几十行代码,确实是个很是棒的举措。先举一个很是简朴的例子,思量对n行的矩阵举办上下翻转,即第i行第n-i+1行交流,一个较量直接的做法就是轮回,码字快的哥们目测几秒钟就能写完,然后矩阵一大呢?一个简朴的交流就要跑半分钟是不是会很不爽?那怎么办?这个时候伟大的高代勇敢的站了出来,上下翻转完全可以用矩阵运算来描写,它不就等价于左乘一个副对角线上均为1,其余均为零的方阵么,于是轻松加愉快搞定!
再举一个例子应用代价更大的例子,是我在刚学多元统计阐明时遇到的,有心寄望了一下,以绘制和谐曲线图(一种通过三角调动实现多元数据可视化的要领,又称andrew曲线,道理请自行百度)为例,先看这一段:
这段代码是出自薛毅、陈丽萍老师《统计建模与R软件》,欠盛情思这里拿来做个反例,可以看到内里用到的for轮回较量多,那么是不长短这些for不行呢?谜底虽然是否认的,再看下一段:
上面的这个问题在这段代码中就已经被办理了,用向量化编程抵抗了for。这是谢大在MSG包的一个function,赞!这里顺便提一句,关于绘制和谐曲线图,还可以利用andrews包,对应的函数为andrews(),成果相对更强大些。
其他关于向量化编程例子举不胜举,网上的例子也很是的多,这里再赘述也没有什么意义,别的这方面进修matlab的向量化编程能力也极有参考代价,因为大概matlab的相关资料更多些。
2 用底层语言:R今朝如此受接待的一个重要原因就在于它有一个很大的利益——提供了很是好的接口,可以很是利便的挪用C、C++、Fortran(有时候也不太利便,但咱好歹给R留点体面么),.C(),package Rcpp都长短常棒的。这给混编好手留了极大的发挥空间,关于混编可以参考Writing R Extensions ,同样附上一个简捷的示例,思量求斐波那契数列,同样较量直观的做法莫过于一个轮回,很是之爽快,同之前所说的上下翻转同属于秒杀型措施,代码如下:
可是写完一跑就没写的时候那么爽,又是for惹的祸, 与上下翻转差异的是这里恐怕高代没法替我们做主了,怎么办?那就用c++吧,于是代码酿成了这样
其实样子差不多,只不外简直快了许多,不信可以数字取大点试试。需要说明的是,CRAN上许多package都操作了这种很是猥琐的要领(不外我打仗的以挪用C可能fortran居多),尤其是跟bayes有关的(为了谁人坑爹的积分),但一个庞大的利益是这个要领是万能的,只要你愿意,理论上可以制止掉所有的for和while。。。。(上述代码不要忘了加载package Rcpp),关于Rcpp包,可以参考该包的几篇小品文:
Rcpp-FAQ
Rcpp-attributes
Rcpp-extending
Rcpp-introduction
Rcpp-modules
Rcpp-package
Rcpp-quickref
Rcpp-sugar
Rcpp-unitTests
#p#分页标题#e#
这里增补一点关于package Rcpp:首先我申明对付这个package的相识并不多,所以也只是随便扯扯,我仔细读过作者写的文档(感受文档较量烂。。。),但其实我并没有贯通太多,我也仅仅学会了简朴的挪用,我以为有些函数都照旧较量好用的,单对大部门成果暗示hold不住,所以我以为这个package较量适合于计较机功底扎实的,但假如只是为了交给C++做一些通例的轮回可能运算之类的,我以为也算较量利便的(事实上我以为也仅需要把通例运算丢给底层语言就行了,否则要R来干嘛呢)。正如某位仁兄所言,别走火入魔就行。
3 隐式轮回:apply系列装逼函数备受亲睐,结果也确实不错,可是它的本质也是挪用底层语言,但是谁让他用起来简朴呢(说实话,代码可读性反而弱了),这个例子就不举了,各类坑爹的中文课本里都有诸如apply(x,1,sum)之类的例子一坨,同样可以参考《统计建模与R软件》,欠盛情思又黑了一下,不是存心的。可是要留意的是,这种要领也是万能的,许多人会有一个误区,就是隐式轮回只能应该于没有担任性的轮回,对,从某种意义上讲没错,因为只有在轮回没有担任性的前提下才是有效的,可是当轮回有担任性时并不是不能用,只不外需要很猥琐的用到全局赋值,照旧以斐波那契数列为例,用apply的代码为:
可是这意味这原本只需要一单元的内存,此刻就要用三个单元了,鉴于本人智商较量拙计,临时想不出破解之道。今朝我的结论依然是该要领装逼代价大于实用代价(因为当轮回没有担任性时尚有更高效的要领,并且apply系列的效率提高许多时候很是有限,而且容易想到apply的话往往能用矩阵运算,乘除Kronecker什么的)。但由于要领万能,所以只要愿意,都可以用,哪怕不会用底层语言,for也可以从代码中彻底退休(假如可以或许忍受某些极度环境的话),可是所谓内存、效率不行兼得。
4 并行计较:谨慎推荐并行计较!貌似最近很火啊~前提是电脑不拙计(好歹也要双核,单核跟谁并行去,并且双核电脑许多时候也没什么结果,横竖前提电脑得达标)的环境下,同样该要领万能,分为两类,一种是轮回无担任,那就很是很是棒,没记错的话在2.14.x系列之后,R就已经将parallel包作为焦点包收入迩来,说明该包长短常之给力的!众所周知,尺度包是质量是没话说的(扩展包就良莠不齐了) ,事实上也简直如此,统计之都R语言大神之一刘思喆在他的一篇博文中有提到,parallel包的一大长处就在于他很是好用。假如已经可以或许很是纯熟的利用apply装逼系列函数的话,那这将秒会,同样附上一个例子:
自行测一下时间就会发明尼玛很是很是棒!
至于为什么这个要领万能,就要提一下坑爹的foreach包,该package的主函数是也是foreach,主要用于替代for,用法与for雷同,照旧用一个例子来说明区别吧:
for: for(i in 1:100){******}
foreach: foreach(i=1:100)%do% ******
至于结果么,我跑出来很坑爹,尚未找出原因,这个功效让我很难有动力去深究这个包,因此在这我也就不下定论了。另外再提一下,compiler包中的cmpfun(对for轮回加快)也值得一用。对并行感乐趣的可以参考Norman Matloff老爷子除了写的《Programming on Parallel Machines》,个中的第十章讲的是Parallel R。虽然他写的《The Art of R programming》也有一个chapter提到了,目测已有中译本《R语言编程艺术》。
其实要领尚有许多几何,上面几种要领相对来说是较量“万能”的,但依然没有一种完美替代法,老天爷还没规划让for退休,那就让它再活几年吧~别的本文的目标只是纯真的想要领来取代轮回,而没有过多的专注于运算效率(进来关于加快R运算的资料层出不穷,想先睹为快的戳link没错的~),或者较量无聊,那就纯属娱乐吧~