我在R中遇到了很大的性能问题.我编写了一个迭代data.frame对象的函数.它只是添加一个新列data.frame并积累一些东西.(操作简单).将data.frame有大约850K行.我的电脑仍在工作(现在大约10小时),我不知道运行时间.
dayloop2 <- function(temp){
for (i in 1:nrow(temp)){
temp[i,10] <- i
if (i > 1) {
if ((temp[i,6] == temp[i-1,6]) & (temp[i,3] == temp[i-1,3])) {
temp[i,10] <- temp[i,9] + temp[i-1,10]
} else {
temp[i,10] <- temp[i,9]
}
} else {
temp[i,10] <- temp[i,9]
}
}
names(temp)[names(temp) == "V10"] <- "Kumm."
return(temp)
}
Run Code Online (Sandbox Code Playgroud)
有什么想法如何加快这个操作?
因此,我们习惯于对每个R新用户说" apply没有矢量化,请查看Patrick Burns R Inferno Circle 4 ",其中说(我引用):
常见的反射是使用apply系列中的函数.这不是 矢量化,而是循环隐藏.apply函数在其定义中有一个for循环.lapply函数掩盖了循环,但执行时间往往大致等于显式for循环.
实际上,快速查看apply源代码会显示循环:
grep("for", capture.output(getAnywhere("apply")), value = TRUE)
## [1] " for (i in 1L:d2) {" " else for (i in 1L:d2) {"
Run Code Online (Sandbox Code Playgroud)
好到目前为止,但看看lapply或vapply实际上揭示了一个完全不同的图片:
lapply
## function (X, FUN, ...)
## {
## FUN <- match.fun(FUN)
## if (!is.vector(X) || is.object(X))
## X <- as.list(X)
## .Internal(lapply(X, FUN))
## }
## <bytecode: 0x000000000284b618>
## <environment: namespace:base>
Run Code Online (Sandbox Code Playgroud)
所以显然没有R for环隐藏在那里,而是他们调用内部C编写的函数.
此外,让我们以 …
我知道循环很慢R,我应该尝试以矢量化的方式做事.
但为什么?为什么循环缓慢且apply速度快?apply调用几个子功能 - 这似乎不快.
更新:对不起,这个问题不合适.我混淆了矢量化apply.我的问题应该是,
"为什么矢量化更快?"
最近关于使用require与::的问题引发了关于在R中编程时使用哪种编程风格的问题,以及它们的优点/缺点.浏览源代码或在网上浏览,您会看到许多不同的样式显示.
我的代码中的主要趋势:
重度矢量化我使用索引(和嵌套索引)玩了很多,这有时会产生相当模糊的代码,但通常比其他解决方案快得多.例如:x[x < 5] <- 0而不是x <- ifelse(x < 5, x, 0)
我倾向于嵌套函数以避免使用我需要清理的临时对象来重载内存.特别是对于操纵大型数据集的函数,这可能是一个真正的负担.例如:y <- cbind(x,as.numeric(factor(x)))而不是y <- as.numeric(factor(x)) ; z <- cbind(x,y)
我编写了很多自定义函数,即使我只在例如一次使用代码.一个sapply.我相信它可以让它更容易阅读,而不会产生可以保持躺着的物体.
我不惜一切代价避免循环,因为我认为矢量化更清洁(更快)
然而,我注意到对此的看法不同,有些人倾向于背弃他们所谓的"Perl"编程方式(甚至是"Lisp",所有这些括号都在我的代码中飞来飞去.我不知道虽然走得那么远.
您认为R中的良好编码实践是什么?
您的编程风格是什么,您如何看待它的优缺点?
作为最佳实践的问题,我试图确定apply()在矩阵中创建函数是否更好,或者如果通过函数简单地循环矩阵更好.我尝试了两种方式,并惊讶地发现apply()速度较慢.任务是取一个向量并将其评估为正数或负数,然后如果为正数则返回1,如果为负则返回-1.该mash()函数循环和squish()功能传递给apply()函数.
million <- as.matrix(rnorm(100000))
mash <- function(x){
for(i in 1:NROW(x))
if(x[i] > 0) {
x[i] <- 1
} else {
x[i] <- -1
}
return(x)
}
squish <- function(x){
if(x >0) {
return(1)
} else {
return(-1)
}
}
ptm <- proc.time()
loop_million <- mash(million)
proc.time() - ptm
ptm <- proc.time()
apply_million <- apply(million,1, squish)
proc.time() - ptm
Run Code Online (Sandbox Code Playgroud)
loop_million 结果:
user system elapsed
0.468 0.008 0.483
Run Code Online (Sandbox Code Playgroud)
apply_million 结果:
user system …Run Code Online (Sandbox Code Playgroud) 人们常说,人们应该更喜欢lapply过for循环.有一些例外,例如Hadley Wickham在他的Advance R书中指出.
(http://adv-r.had.co.nz/Functionals.html)(修改到位,递归等).以下是这种情况之一.
仅仅为了学习,我试图以功能形式重写感知器算法,以便对相对性能进行基准测试.来源(https://rpubs.com/FaiHas/197581).
这是代码.
# prepare input
data(iris)
irissubdf <- iris[1:100, c(1, 3, 5)]
names(irissubdf) <- c("sepal", "petal", "species")
head(irissubdf)
irissubdf$y <- 1
irissubdf[irissubdf[, 3] == "setosa", 4] <- -1
x <- irissubdf[, c(1, 2)]
y <- irissubdf[, 4]
# perceptron function with for
perceptron <- function(x, y, eta, niter) {
# initialize weight vector
weight <- rep(0, dim(x)[2] + 1)
errors <- rep(0, niter)
# loop over number of …Run Code Online (Sandbox Code Playgroud) 我想知道如何迭代R中列表对象的键/值对,如下例所示:
toto <- list(a="my name is",b="I'm called",c="name:")
myfun <- function(key,value) paste(value,key)
for( key in names(toto) ) toto[key] <- myfun(key,toto[[key]])
Run Code Online (Sandbox Code Playgroud)
有没有办法避免for循环(使用lapply()或类似).会更快吗?
谢谢!
我经常想做以下几点:
mat <- matrix(0,nrow=10,ncol=1)
lapply(1:10, function(i) { mat[i,] <- rnorm(1,mean=i)})
Run Code Online (Sandbox Code Playgroud)
但是,我希望mat里面会有10个随机数,但它有0个.(我并不担心rnorm部分.显然有一种正确的方法可以做到这一点.我担心会影响mat lapply的匿名函数)我可以不从lapply里面影响矩阵垫吗?为什么不?是否有R的范围规则阻止了这个?
从矩阵中的每列中提取min的最快方法是什么?
将所有基准移至下面的答案.
## TEST DATA
set.seed(1)
matrix.inputs <- list(
"Square Matrix" = matrix(sample(seq(1e6), 4^2*1e4, T), ncol=400), # 400 x 400
"Tall Matrix" = matrix(sample(seq(1e6), 4^2*1e4, T), nrow=4000), # 4000 x 40
"Wide-short Matrix" = matrix(sample(seq(1e6), 4^2*1e4, T), ncol=4000), # 40 x 4000
"Wide-tall Matrix" = matrix(sample(seq(1e6), 4^2*1e5, T), ncol=4000), # 400 x 4000
"Tiny Sq Matrix" = matrix(sample(seq(1e6), 4^2*1e2, T), ncol=40) # 40 x 40
)
Run Code Online (Sandbox Code Playgroud) r ×10
performance ×4
apply ×2
benchmarking ×2
lapply ×2
loops ×2
coding-style ×1
function ×1
matrix ×1
min ×1
r-faq ×1
rcpp ×1