高效完成R代码

为什么R有时候运行慢?

参考https://www.cnblogs.com/qiaoyihang/p/7779144.html

一、为什么R程序有时候会很慢?

1、计算性能的三个限制条件 cpu ram io R代码本身(个人觉得能控制的是R代码书写的高效
2、R是运行时解释的 在运行时解释并执行R代码
3、R是单线程的 CPU的强大核心并没卵用,R只会只用一个
4、R需要将全部数据加载到内存 处理的最大数据了取决于内存的限制
这里 linux相比于windows有一个优势,当我们试图装载一个可用内存大小的数据集
数据可能会成功装载,不过一旦可用内存耗尽,操作系统会将内存中的数据换到磁盘(交换空间)上
的交换文件,R人为数据全部装载入内存时间上OS正在做内存和磁盘文件的数据交换工作,如此一来,磁盘IO瓶颈对R性能就有着巨大的影响
5、算法设计影响时间和空间复杂度
时间复杂度:运行R程序需要的计算时间和数据规模之间的关系
空间复杂度:运行R程序需要的内存量和数据规模之间的关系

二、衡量代码的性能常用办法

使用system.time() benchmark() microbenchmark()
Rprof() 的工作原理是在运行R表达式的时候 ,观察R的调用栈,并以固定的时间,默认是0.02秒,对调用栈进行快照
,从而确定函数当前正在执行什么操作。通过这些快照,summaryRprof 能够计算每个函数的耗时
要理解R程序各个部分的性能,快速发现瓶颈,Rprof 是个很有用的工具
内存分析 memory.profiling=TRUE 这个指标会有误导,会偏高,因为有些函数内存尚未释放,

三、加快R运行的简单方法

1、尽量向量化运算,避免循环(这个一定要注意,我稀罕循环,然后容易die)

2、使用内置函数。 R中存在很多低级运算符,虽然这些运算符可以组成更加复杂的运算符或者函数,但是和编译性语言相比性能很差,
但是R提供了很多C++编写的计算包。(大量的内置函数可以使用,所以不需要像python一样)百度一下都能解决内置函数问题。。

比如计算 矩阵每一行的和,一般用apply可以解决问题,但是内置函数 rowSums,性能提升11倍,rowSums是使用C预编译的优化函数
开源社区开发了很多函数优化库供R使用,比如 basic linear algebra subprograms (BLAS) 详见:www.netlib.org.blas
给个demo好了

> # Define the previous solution
> app <- function(x) {
      apply(x, 1, sum)
  }
>
> # Define the new solution
> r_sum <- function(x) {
      rowSums(x)
  }
>
> # Compare the methods
> microbenchmark(
      app_sol = app(rolls),
      r_sum_sol = r_sum(rolls)
  )
Unit: microseconds
      expr    min     lq     mean  median      uq      max neval
   app_sol 27.482 28.434 50.85846 29.0660 30.6125 2004.209   100
 r_sum_sol  6.709  7.673 27.95393  8.3015  8.7205 1956.351   100
实行的函数功能一样,从运行时间上来看 rowSums()效率更高

3、预分配内存
上回跑了一个pmg模型,我的电脑崩了。。。事先没有进行预估计
为什么要预分配内存呢?主要是因为动态分配内存会拖慢程序的运行速度,每当向量大小发生变化,程序都需要做一些额外的工作
经过测试在一个简单的加法运算中,1000 长度的向量的计算,预分配内存之前为25.373秒,之后为0.577 秒
4、使用简单的数据结构
5、使用更加简单的数据结构
比如 如果可以的话,尽量使用matrix 而不是 dataframe,因为大部分矩阵操作首先要把dataframe强制转换为matrix,才开始计算。额好吧,其实我都是用dataframe的。
mat是一个矩阵,df是一个数据框,比较一下二者的运行速度

> # Which is faster, mat[, 1] or df[, 1]?
> microbenchmark(mat[, 1], df[, 1])
Unit: microseconds
     expr    min     lq     mean  median      uq    max neval
 mat[, 1]  2.318  2.701  3.21188  2.9760  3.3265 18.359   100
  df[, 1] 11.646 13.010 16.67619 13.8965 15.1355 95.352   100

如果数据中存在多种变量类型,不可避免的要使用dataframe的时候,尽量用subset 和 which 筛选子集后再做运算。
6、使用哈希表进行大型数据上的频繁查找
一个包含N个元素的列表上的查找操作的时间复杂度是O(N) 列表越靠后,查找时间越长,随着N的增加,情况越严重。
CRAN 上可用的R 包是hash, 哈希表上查找操作的时间复杂度为O(1)
7、去CRAN上寻找更快的包
例如:fastcluster,princomp,fastmatch,RcppEigen,data.table,dplyr

四、使用编译代码加快运行速度

1、在运行之前编译R代码 因为每次运行前都需要解析和评估代码。这需要话费大量CPU时间,拖慢运行速度。
利用compiler 包,能在一定程度上减少此问题,提前预编译。
cmpfun 编译函数
compile 编译表达式
cmpfile 编译存储在文件中的R表达式
2、即时编译 激活JIT(just in time) compiler 包的enableJIT
3、在R中使用编译语言 在R中嵌入C、C++、OC、OC++(inline包)
4、调用外部编译代码 Rcpp rJava
5、使用编译代码的注意事项
6、创建R对象及垃圾回收
预分配变量内存,PROTECT防止R的垃圾收集器清理对象。 UNPROTECT 解除已分配内存的保护
7、One thing to note is that && only works on single logical values, i.e., logical vectors of length 1 (like you would pass into an if condition), but & also works on vectors of length greater than 1.
从运行时间上面来看确实是&更快一些

> # Example data
> is_double
[1] FALSE  TRUE  TRUE
>
> # Define the previous solution
> move <- function(is_double) {
      if (is_double[1] & is_double[2] & is_double[3]) {
          current <- 11 # Go To Jail
      }
  }
>
> # Define the improved solution
> improved_move <- function(is_double) {
      if (is_double[1] && is_double[2] && is_double[3]) {
          current <- 11 # Go To Jail
      }
  }
>
> # microbenchmark both solutions
> # Very occassionally the improved solution is actually a little slower
> # This is just random chance
> microbenchmark(move, improved_move, times = 1e5)
Unit: nanoseconds
          expr min lq     mean median  uq    max neval
          move  42 52 107.7818    133 141 110084 1e+05
 improved_move  39 50 104.0745    130 138  41764 1e+05

五、使用GPU让R运行的更快
这里需要注意的是在计算pearson相关性的时候,GPU是比CPU慢的
1、GPU最大的优势是核心数量巨多,所以最适合数据的并行问题,不适合那些线程之间需要大量同步的任务。
2、GPU的性能主要取决于主内存(RAM)和GPU内存之间的数据传输量,因为RAM和CPU内存之间的连接宽带很低。
优秀的GPU编程应该最小化这种传输

1.查看R 当前的版本

主要是查看配置信息把

 # Print the R version details using version
> version
               _
platform       x86_64-pc-linux-gnu
arch           x86_64
os             linux-gnu
system         x86_64, linux-gnu
status
major          3
minor          4.4
year           2018
month          03
day            15
svn rev        74408
language       R
version.string R version 3.4.4 (2018-03-15)
nickname       Someone to Lean On
>
> # Assign the variable major to the major component
> major <- version$major
>
> # Assign the variable minor to the minor component
> minor <- version$minor

2.读入数据更高效

Comparing read times of CSV and RDS files
One of the most common tasks we perform is reading in data from CSV files. However, for large CSV files this can be slow. One neat trick is to read in the data and save as an R binary file (rds) using saveRDS(). To read in the rds file, we use readRDS().

Note: Since rds is R‘s native format for storing single objects, you have not introduced any third-party dependencies that may change in the future.

To benchmark the two approaches, you can use system.time(). This function returns the time taken to evaluate any R expression. For example, to time how long it takes to calculate the square root of the numbers from one to ten million, you would write the following:

> # How long does it take to read movies from CSV?
> system.time(read.csv("movies.csv"))
   user  system elapsed
  0.395   0.000   0.395
>
> # How long does it take to read movies from RDS?
> system.time(readRDS("movies.rds"))
   user  system elapsed
  0.042   0.000   0.042

不难看出,rds是更高效的,因为数据是加载到R里面的,比外部导入里面之后加载肯定要节省时间。。(或许这么解释不对,但是真的节省时间)

3.辨析 <-和=

这两个是不一样的
Using the <- operator inside a function call will create a new (or overwrite an existing) object.
<-创建的变量的作用范围可以在整个顶层环境,而=仅仅在一个局部环境。(应该是global和局部的关系)https://www.cnblogs.com/xuanlvshu/p/5493222.html
但要<-创建的变量如果是在函数实参传递的时候创建的,其的作用范围可以在整个顶层环境,有一个前提条件:对应的形参在函数内部被用到了。

4.microbenchmark

> # Load the microbenchmark package
> library(microbenchmark)
>
> # Compare the two functions
> compare <- microbenchmark(read.csv("movies.csv"),
                            readRDS("movies.csv"),
                            times = 10)
>
> # Print compare
> compare
Unit: nanoseconds
     expr min  lq  mean median  uq  max neval
 read.csv 145 148 414.4    150 158 2741    10
  readRDS 110 114 173.1    116 124  681    10

The benchmarkme package provides a set of benchmarks to help quantify your system. More importantly, it allows you to compare your timings with other systems.

> # Load the benchmarkme package
> library( benchmarkme)
>
> # Assign the variable ram to the amount of RAM on this machine
> ram <- get_ram()
> ram
16.3 GB
>
> # Assign the variable cpu to the cpu specs
> cpu <- get_cpu()
> cpu
$vendor_id
[1] "GenuineIntel"
$model_name
[1] "Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz"
$no_of_cores
[1] 4

get_ram():Attempt to extract the amount of RAM on the current machine.
get_cpu():Attempt to extract the CPU model on the current host
pre_allocate():测试边;变量声明的时间的
The growing() function defined below generates n random standard normal numbers, but grows the size of the vector each time an element is added!

向量化代码有多重要?

profvis:Profvis is a tool for visualizing code profiling data from R. It creates a web page which provides a graphical interface for exploring the data. Live demo.

比如这个是可以在网页上面看到的

How many cores does this machine have?

The parallel package has a function detectCores() that determines the number of cores in a machine.
How many cores does this machine have?

一个改写sapply和parSapply的例子

> # Set the number of games to play
> no_of_games <- 1e5
>
> ## Time serial version
> system.time(serial <- sapply(1:no_of_games, function(i) play()))
   user  system elapsed
  7.003   0.005   7.018
>
> ## Set up cluster
> cl <- makeCluster(4)
> clusterExport(cl, "play")
>
> ## Time parallel version
> system.time(par <- parSapply(cl, 1:no_of_games, function(i) play()))
   user  system elapsed
  0.063   0.004   3.168
>
> ## Stop cluster
> stopCluster(cl)

原文地址:https://www.cnblogs.com/gaowenxingxing/p/12019488.html

时间: 2024-10-23 13:31:12

高效完成R代码的相关文章

A1128 | 逻辑想象能力、简洁高效美观的代码、memset的使用情景

写了三遍才AC,这真是对智商极大的侮辱 C++代码: #include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include &l

机器学习系列(9)_机器学习算法一览(附Python和R代码)

本文资源翻译@酒酒Angie:伊利诺伊大学香槟分校统计学同学,大四在读,即将开始计算机的研究生学习.希望认识更多喜欢大数据和机器学习的朋友,互相交流学习. 内容校正调整:寒小阳 && 龙心尘 时间:2016年4月 出处:http://blog.csdn.net/han_xiaoyang/article/details/51191386 http://blog.csdn.net/longxinchen_ml/article/details/51192086 声明:版权所有,转载请联系作者并注

高效的CSS代码(2)

——阅读笔记,欢迎纠错^_^ 内容比较零散..... 1.让浮动元素的父容器根据元素的高度而自适应高度的方法: <div class="clearfix"><div class="fl"></div></div> /*意思就是最外面的一层<div></div>是父容器,给他加上清除浮动的功能,clearfix的代码再高效的CSS代码(1)中有*/ 2.再写代码前不是要先分析一下页面的模块吗,模块

&lt;转&gt;机器学习系列(9)_机器学习算法一览(附Python和R代码)

转自http://blog.csdn.net/han_xiaoyang/article/details/51191386 – 谷歌的无人车和机器人得到了很多关注,但我们真正的未来却在于能够使电脑变得更聪明,更人性化的技术,机器学习. – 埃里克 施密特(谷歌首席执行官) 当计算从大型计算机转移至个人电脑再转移到云的今天,我们可能正处于人类历史上最关键的时期.之所以关键,并不是因为已经取得的成就,而是未来几年里我们即将要获得的进步和成就. 对我来说,如今最令我激动的就是计算技术和工具的普及,从而带

神经网络模型及R代码实现

一.神经网络基本原理 神经元模型 图中x1~xn是从其他神经元传来的输入信号,wij表示表示从神经元j到神经元i的连接权值,θ表示一个阈值 ( threshold ),或称为偏置( bias ).则神经元i的输出与输入的关系表示为: 图中 yi表示神经元i的输出,函数f称为激活函数 ( Activation Function )或转移函数 ( Transfer Function ) ,net称为净激活(net activation).若将阈值看成是神经元i的一个输入x0的权重wi0,则上面的式子

如何编写高效的Android代码

时间是很宝贵的东西,在编写Android代码的时候尽可能的编写出高效的Android代码可以节省你很多的时间,让你有时间去泡妞.去陪女朋友.去陪基友,去吃饭.去娱乐.去睡觉!毕竟,谁都不想整夜整夜的加班,然后还乱吼:时间都去哪了?!下面就整理了怎样提高效率,编写高效的Android代码!看到这,偷笑了吧,表掩饰,我已看到! 对于如何判断一个系统的不合理,这里有两个基本的原则: 一.不要做不必要做的事情. 二.尽可能的节省内存的使用优化链接: http://c.tieba.baidu.com/p/

R 代码积累

R 代码积累不定期更新 1.阶乘.递归.reduce.sprintf #NO.1 # 阶乘函数 fact <- function(n){ if(n==0) return(1) #基例在这 else return(n*fact(n-1)) } #1+2!+3!+...+20!的和 #测试 Reduce('+', lapply(1:3,fact)) 结果是9 Reduce('+', lapply(1:20,fact)) #NO.2 #判断101-200之间有多少个素数,并输出所有素数 is.prim

编写高效的Android代码

为什么在这就意味着没有多少剩余空间给你去浪费了,因此,在你写Androi编写Android程序时要时刻考虑执行的效率,这些系统不是想象中的那么快,并且你还要考虑它电池的续航能力.写程序的时候,要尽可能的使你的代码优化而提高效率. 对于如何判断一个系统的不合理,这里有两个基本的原则: 1.不要做不必要做的事情. 2.尽可能的节省内存的使用. 下面是常用的几点优化建议: 1.尽可能避免创建对象(Object) 因为对象的创建并不是没有代价的,如果你在一个用户界面的循环中分配一个对象,你不得不强制的进

可以编辑R代码的eclipse插件

说到强大的IDE,eclipse肯定是首先会被想到的几个之一,幸运地是,R也能使用它.在http://www.walware.de/goto/statet上有个StatET的插件,专门为R而做,从此R就能在eclipse的平台上享用一切eclipse的功能. 如果机器上没有eclipse,可以在网上JAVA相关的社区找到很多很详细的教程,JRE和R中的rJava包是必需的,建议最好顺便把JDK也装上,eclipse的环境都搭好了,不用JAVA太可惜了,能写R程序的人肯定也能写JAVA程序,R和J