[笔记]提升R的性能和突破内存限制的技巧
本文為雪晴數據網《R語言大規模數據分析實戰》 http://www.xueqing.tv/course/56 的課程學習筆記。
該課程目前更新到“第2章 Microsoft R Server簡介”的微軟數據科學家介紹MRS,后續教學主要是關于MRS的內容,再另外學習,所以本文只學習“第1章 提升R的性能和突破內存限制的技巧”。
1. 課程介紹
1.1 課程目錄
第一章 突破R內存瓶頸的一些小技巧
升級硬件和軟件
減少數據復制
利用整數的優勢
有效地存儲數據
在轉換數據的時候避免循環
在關鍵函數里使用C、C++或Fortran
盡可能地使用面向行的數據轉換
排序之前要三思
使用bigmemory家族的包
借助數據庫
使用Revolution R Enterprise(簡稱RRE)
第二章 RRE的簡介
RRE學術版的下載與安裝
RRE的功能介紹
導入數據的函數
概括數據的函數
RRE可視化功能
RRE所支持的算法介紹
第三章 用RRE做數據探索
導入數據
用rxGetVarInfo()函數查看數據的基本特征
用rxSummary()函數計算數據的描述統計量
用rxHistogram()分析數據的分布
用rxLinePlot()可視化分析兩個變量之間的關系
用rxCrossTabs()分析變量間的關系
用with rxCube()分析變量間的關系
第四章 用RRE做數據整理
數據融合
用rxDataStep()做數據變換
用dplyrXdf包整理數據
第五章 用RRE做數據挖掘(案例實戰)
數據準備
導入數據
數據探索
線性回歸
邏輯回歸
K-means聚類
決策樹分類
1.2 課程視頻目錄
第1章:提升R的性能和突破內存限制的技巧
如何提升R的性能
并行計算
第2章:Microsoft R Server簡介
微軟數據科學家介紹MRS
2. 第1章:提升R的性能和突破內存限制的技巧
2.1 如何提升R的性能
這一節先介紹提高R性能的幾種方法,然后重點介紹如何利用R的內部機制來提升性能。
2.1.1 性能提升的方法
a.1 系統升級
升級硬件
使用64位操作系統
利用GPU
租用云計算服務器
a.2 開發層面的優化
算法
降低算法復雜度調用C/C++或者Fortran
關鍵的、耗時的計算步驟緩沖技術
減少重復計算
a.3 使用層面的優化
充分利用R的內存機制——R的基礎優化
增強R的矩陣運算——加速BLAS
并行計算
大規模數據的處理——圖片內存限制
使用Revolution R Enterprise(RRE)
下列介紹通過充分利用R的內部機制優化性能
2.1.2 向量化
向量化的代碼,不要用循環!
利用矩陣運算
利用內置的向量化函數,比如exp、sin、rowMeans、rowSums、colSums、ifelse等
利用Vectorize函數將非向量化的函數改裝為向量化的函數
*apply函數族:apply、lapply、sapply、tapply、mapply等
plyr和dplyr包
Rstudio發布的data wrangling cheat sheet
利用R內置的向量化函數,自定義向量化函數,只要在函數定義時每個運算是向量化的。但是在函數定義時用了邏輯判斷語句,就會破壞的向量化特征。
func <- function(x){if(x %% 2 == 0){ret <- TRUE}else{ret <- FALSE}return(ret) } func(34) func(c(1,2,3,4)) ## Warning message: ## In if (x%%2 == 0) { : ## the condition has length > 1 and only the first element will be used ## 在函數的定義中有if語句,不能接受向量作為判斷的條件,否則判斷第一個元素。## 利用ifelse函數做向量化的判斷 myfunc <- function(x){ifelse(x %% 2 == 0,TRUE,FALSE) } myfunc(c(1,2,3,4))##利用Vectorize函數將非向量化的函數改裝為向量化的函數 funcv <- Vectorize(func) funcv(c(1,2,3,4))##利用sapply函數向量化運算 sapply(c(1,2,3,4),func)2.1.3 預先給對象分配內存
R為解釋性語言,也是動態語言,如果不事先指定對象的類型和長度,在運算過程會動態分配內存,提高靈活性,但降低了效率。
盡量減少cbind、rbind的使用
## 求出10000個斐波那契數 x <- c(1,1) i <- 2 system.time(while(i<10000){new <- x[i] + x[i-1]x <- cbind(x,new)i <- i + 1} )## 指定類型和長度 x <- vector(mode="numeric",100000) x[1] <- 1 x[2] <- 1 system.time(while(i<10000){i <- i + 1x[i] <- x[i-1] + x[i-2]} )2.1.4 避免內存拷貝
假設我們有許多彼此不相關的向量,但因為一些其他的原因,我們希望將每個向量的第三個元素設為8,既然它們是互不相關的,甚至可能具有不同的長度,我們也許會考慮將它們放在一個列表中:
m <- 5000 n <- 1000 z <- list() for(i in 1:m) z[[i]] <- sample(1:10, n, replace = T) system.time(for(i in 1:m) z[[i]][3] <- 8)## 把這些向量一起放到矩陣中 z <- matrix(sample(1:10, m * n, replace = T),nrow = m) system.time(z[,3] <- 8)2.1.5 刪除臨時對象和不再用的對象
rm()刪除對象
rm(object)刪除指定對象,rm(list = ls())可以刪除內存中的所有對象gc()內存垃圾回收
使用rm(object)刪除變量,要使用gc()做垃圾回收,否則內存是不會自動釋放的。invisible(gc())不顯示垃圾回收的結果
2.1.6 分析內存的函數
ls()列出特定環境中的對象
object.size()返回R對象的大小(近似的)
memory.profile()分析cons單元的使用情況
memory.size()監測全部內存的使用情況(僅Windows下可用)
memory.size(max=T)返回歷史占用過的最大內存;memory.size(max=F)返回目前占用的內存。未做垃圾清理時,已使用內存和已分配內存同步增加,但在垃圾清理后rm(list=ls());gc(),已使用內存會減少,而已分配給R的內存不會改變。memory.limit()系統可分配的內存上限(僅Windows下可用)
memory.limit(newLimit)更改到一個新的上限。 注意,在32位的R中,封頂上限為4G,你無法在一個程序上使用超過4G (數位上限)。這種時候,可以考慮使用64位的版本。
2.2 并行計算
本節主要介紹parallel包,后續介紹R與Hadoop的結合
2.2.1 parallel包
parallel包實際上整合了之前已經比較成熟的snow包和multicore包,multicore無法在windows下運行。
## 一個簡單的例子 system.time(for(i in 1:4){Sys.sleep(2)}) ## 或者用lapply改寫成: system.time(lapply(1:4, function(i) Sys.sleep(2))) ## 設置并行環境 library(parallel) ## 檢測系統可用的核數 detectCores() ## 默認返回的結構邏輯的核數,需修改logical=FALSE,返回物理核數 detectCores(logical=FALSE) ## 建立2核的集群 cl <- makeCluster(2)## 不使用并行計算 system.time(lapply(1:4, function(i) Sys.sleep(2)))## 使用parallel包,運行時間減半 ## 在非windows系統下,使用mclapply函數 system.time(mclapply(1:4, function(i) Sys.sleep(2),mc.cores=2) ) ## 在windows系統下,使用parlapply函數 system.time(parlapply(cl, 1:4 function(i) Sys.sleep(2)) )##關閉集群 stopCluster(cl)2.2.2 foreach和doParallel包
使用parallel包進行并行運算時,需改寫原來的程序,且改寫較多。
foreach包是一個并行計算的框架:循環控制+并行執行。foreach相當于for的延伸,在循環的過程中它能夠選擇不同的并行后段進行執行。在非并行運算過程中代替for。改寫為并行運算,改寫很少。
## 一個簡單的例子 ## 不并行的版本 library(foreach) foreach(i=1:4) %do% sqrt(i) ## .combine則表示運算結果的整合方式,.combine='c'運算結果為向量 foreach(i=1:4,.combine='c') %do% sqrt(i) system.time(foreach(i=1:4) %do% sqrt(i)) ## 并行的版本,需要把%do%改為%dopar% system.time(foreach(i=1:4) %dopar% sqrt(i)) ## 并行計算失敗!用foreach做并行計算必須跟并行后端(parallel backend)配合使用
doParallel包時foreach包執行并行計算時的后端接口程序。
CRAN上還有以下的并行計算后端包:
doMPI與Rmpi包配合使用
doRedis與rredis包配合使用
doMC提供parallel包的多核計算接口
doSNOW提供現已廢棄的SNOW包的接口
案例
library(parallel) cl <- makeCluster(2) fun <- function(x){return(x+1) } ## 不并行計算效果 system.time(res <- lapply(1:5000000, fun) ) ## parallel并行計算效果 system.time(res <- mclapply(1:5000000, fun, mc.cores=2) ) ## foreach并行計算效果 library(foreach) library(doParallel) registerDoParallel(cl) system.time(res <- foreach(x=1:5000000,.combine='cbind') %dopar%fun(x) )## 關閉集群 stopCluster(cl)parallel并行計算速度比不并行計算速度稍微快點,而foreach并行計算速度比不并行計算還慢很多很多,不知道是什么原因
不知何故,在Mac OSX 下采用doParallel速度特別慢, 比不用并行還慢,于是又嘗試了doMC
library(doMC) ## 設置并行核數, 并注冊并行 registerDoMC(2) ## 開始計算 system.time(foreach(i=1:4) %dopar% sqrt(i))## 比較不并行計算和doParallel并行計算 system.time(foreach(i=1:4) %do% sqrt(i)) cl <- makeCluster(2) registerDoParallel(cl) system.time(foreach(i=1:4) %dopar% sqrt(i))doMC比doParallel還慢!
Getting Started with doParallel and foreach的解釋如下:
With small tasks, the overhead of scheduling the task and returning the result can be greater than the time to execute the task itself, resulting in poor performance. In addition, this example doesn’t make use of the vector capabilities of sqrt, which it must to get decent performance. This is just a test and a pedagogical example, not a benchmark.
對于小任務,調度任務并返回結果的開銷可能比執行任務本身還耗時,導致表現不佳。
下列為實際的例子
x <- iris[which(iris[,5] != "setosa"), c(1,5)] trials <- 10000 ptime <- system.time({r <- foreach(icount(trials), .combine=cbind) %dopar% {ind <- sample(100, 100, replace=TRUE)result1 <- glm(x[ind,2]~x[ind,1], family=binomial(logit))coefficients(result1)} })stime <- system.time({r <- foreach(icount(trials), .combine=cbind) %do% {ind <- sample(100, 100, replace=TRUE)result1 <- glm(x[ind,2]~x[ind,1], family=binomial(logit))coefficients(result1)} }) ptime stime3. 參考資料
有沒有高人能使得R迅速釋放占的內存 http://cos.name/cn/topic/139522/
也談提高R語言的運算效率 http://cos.name/2009/12/impro...
R語言并行計算的原理和案例 http://www.tbk.ren/article/63...
R高性能包介紹與并行運算 http://www.idatacamp.com/2015...
R語言 并行處理 http://cangfengzhe.github.io/...
Getting Started with doParallel and foreach https://cran.r-project.org/we...
parallel http://stat.ethz.ch/R-manual/...
總結
以上是生活随笔為你收集整理的[笔记]提升R的性能和突破内存限制的技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决Maven报错“Cannot res
- 下一篇: vue 开发规范