高階程式設計--編寫有效的程式碼(有效的資料輸入、向量化、並行化)
高階程式設計--編寫有效的程式碼
在程式設計師中間流傳著一句話:“優秀的程式設計師是花一個小時來除錯程式碼而使得它的運算速度提高一秒的人。”R是一種鮮活的語言,大多數使用者不用擔心寫不出高效的程式碼。作為一般規則,讓程式碼易於理解、易於維護比優化它的速度更重要。但是當你使用大型資料集或處理高度重複的任務時,速度就成為一個問題了。
幾種編碼技術可以使你的程式更高效:
q 程式只讀取需要的資料。
q 儘可能使用向量化替代迴圈。
q 建立大小正確的物件,而不是反覆調整。
q 使用並行來處理重複、獨立的任務。
1. 有效的資料輸入
使用read.table()函式從含有分隔符的文字檔案中讀取資料的時候,你可以通過指定所需的變數和它們的型別實現顯著的速度提升。這可以通過包含
my.data.frame <- read.table(mytextfile, header=TRUE, sep=',',
colClasses=c("numeric", "numeric", "character",
NULL, "numeric", NULL, "character", NULL,
NULL, NULL))
將比下面的程式碼執行得更快:
my.data.frame <- read.table(mytextfile, header=TRUE, sep=',')
2. 向量化
在有可能的情況下儘量使用向量化,而不是迴圈。這裡的向量化意味著使用R中的函式,這
些函式旨在以高度優化的方法處理向量。初始安裝時自帶的函式包括 ifelse()、colsums()、
rowSums()和rowMeans()。matrixStats包提供了很多進行其他計算的優化函式,包括計數、
求和、乘積、集中趨勢和分散性、分位數、等級和分級的措施。plyr、dplyr、reshape2和
data.table等包也提供了高度優化的函式。
考慮一個1 000 000行10列的矩陣。讓我們使用迴圈並且再次使用colSums()函式來計算列的和。首先,建立矩陣:
set.seed(1234)
mymatrix <- matrix(rnorm(10000000), ncol=10)
然後,建立一個accum()函式來使用for迴圈獲得列的和:
accum <- function(x){
sums <- numeric(ncol(x))
for (i in 1:ncol(x)){
for(j in 1:nrow(x)){
sums[i] <- sums[i] + x[j,i]
}
}
}
system.time()函式可以用於確定CPU的數量和執行該函式所需的真實時間:
system.time(accum(mymatrix))
使用colSums()函式計算和的時間:
system.time(colSums(mymatrix))
結果分析:很明顯,向量化的執行速度更快
3. 並行化
並行化包括分配一個任務,在兩個或多個核同時執行組塊,並把結果合在一起。這些核心可能是在同一臺計算機上,也可能是在一個叢集中不同的機器上。需要重複獨立執行數字密集型函式的任務很可能從並行化中受益。這包括許多蒙特卡羅方法(Monte Carlo method),如自助法(bootstrapping)。
R中的許多包支援並行化,參見Dirk Eddelbuettel的“CRAN Task View: High-Performance andParallel Computing with R”(http://mng.bz/65sT)。在本節中,你可以使用foreach和doParallel
包在單機上並行化執行。foreach包支援 foreach迴圈構建(遍歷集合中的元素)同時便於並行執行迴圈。doParallel包為foreach包提供了一個平行的後端。
(1)foreach和doParallel包的並行化
#(1)載入包並登記核心數量
install.packages("foreach")
library(foreach)
install.packages("doParallel")
library(doParallel)
library(iterators)
library(parallel)
registerDoParallel(cores=4)
#(2)定義函式,在這裡分析100 000×100的隨機資料矩陣。使用foreach和%do%執行eig()函式500次
eig <- function(n, p){
x <- matrix(rnorm(100000), ncol=100)
r <- cor(x)
eigen(r)$values
}
n <- 1000000
p <- 100
k <- 500
#(3)正常執行
system.time(
x <- foreach(i=1:k, .combine=rbind) %do% eig(n, p)
)
#(4)並行執行,system.time( %do%操作符按順序執行函式,.combine=rbind操作符追加物件x作為行。最後,函式使用%dopar%操作符進行並行運算
x <- foreach(i=1:k, .combine=rbind) %dopar% eig(n, p)
)
本文來自部落格園,作者:zhang-X,轉載請註明原文連結:https://www.cnblogs.com/YY-zhang/p/15154260.html