本文爲雪晴數據網《R語言大規模數據分析實戰》 http://www.xueqing.tv/course/56 的課程學習筆記。html
該課程目前更新到「第2章 Microsoft R Server簡介」的微軟數據科學家介紹MRS,後續教學主要是關於MRS的內容,再另外學習,因此本文只學習「第1章 提高R的性能和突破內存限制的技巧」。git
第一章 突破R內存瓶頸的一些小技巧github
升級硬件和軟件web
減小數據複製redis
利用整數的優點算法
有效地存儲數據數據庫
在轉換數據的時候避免循環windows
在關鍵函數裏使用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章:提高R的性能和突破內存限制的技巧
如何提高R的性能
並行計算
第2章:Microsoft R Server簡介
微軟數據科學家介紹MRS
這一節先介紹提升R性能的幾種方法,而後重點介紹如何利用R的內部機制來提高性能。
a.1 系統升級
升級硬件
使用64位操做系統
利用GPU
租用雲計算服務器
a.2 開發層面的優化
算法
下降算法複雜度
調用C/C++或者Fortran
關鍵的、耗時的計算步驟
緩衝技術
減小重複計算
a.3 使用層面的優化
充分利用R的內存機制——R的基礎優化
加強R的矩陣運算——加速BLAS
並行計算
大規模數據的處理——圖片內存限制
使用Revolution R Enterprise(RRE)
下列介紹經過充分利用R的內部機制優化性能
向量化的代碼,不要用循環!
利用矩陣運算
利用內置的向量化函數,好比exp、sin、rowMeans、rowSums、colSums、ifelse等
利用Vectorize函數將非向量化的函數改裝爲向量化的函數
*apply函數族:apply、lapply、sapply、tapply、mapply等
plyr和dplyr包
Rstudio發佈的data wrangling cheat sheet
##利用矩陣運算 n <- 100000 x1 <- 1:n x2 <- 1:n y <- vector() system.time( for(i in 1:n){y[i] <- x1[i] + x2[i]} ) system.time(y <- x1 + x2) ## 利用向量化運算 ## 內置的向量化函數 v <- 1:100000 result <- rep(1:100000) system.time( for(i in 1:100000){result[i] <- sin(v[i])} ) system.time(result <- sin(v)) ## 利用rowMeans、rowSums、colSums、colMeans等函數對矩陣或數據庫作總體處理 colSums(iris[,1:4])
利用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)
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 + 1 x[i] <- x[i-1] + x[i-2] } )
假設咱們有許多彼此不相關的向量,但由於一些其餘的緣由,咱們但願將每一個向量的第三個元素設爲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)
rm()
刪除對象
rm(object)刪除指定對象,rm(list = ls())能夠刪除內存中的全部對象
gc()
內存垃圾回收
使用rm(object)刪除變量,要使用gc()作垃圾回收,不然內存是不會自動釋放的。invisible(gc())不顯示垃圾回收的結果
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位的版本。
本節主要介紹parallel包,後續介紹R與Hadoop的結合
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)
使用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(foreach) ## 註冊並行後端 library(doParallel) cl <- makeCluster(2) registerDoParallel(cl) ## 使用doParallel包作foreach的並行後端 system.time(foreach(1:4) %dopar% Sys.sleep(2)) system.time(for(i in 1:400){sqrt(i)}) system.time(lapply(1:400, function(i) sqrt(i))) system.time(foreach(i=1:400) %do% sqrt(i)) system.time(foreach(i=1:400) %dopar% sqrt(i)) system.time(foreach(i=1:400,.combine='c') %dopar% sqrt(i)) ## foreach和doParallel並行計算速度比不併行計算還慢不少 ## 關閉集羣 stopCluster(cl)
案例
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 stime
有沒有高人能使得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/...