【发布时间】:2017-07-12 15:07:44
【问题描述】:
人们常说应该更喜欢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 epochs niter
for (jj in 1:niter) {
# loop through training data set
for (ii in 1:length(y)) {
# Predict binary label using Heaviside activation
# function
z <- sum(weight[2:length(weight)] * as.numeric(x[ii,
])) + weight[1]
if (z < 0) {
ypred <- -1
} else {
ypred <- 1
}
# Change weight - the formula doesn't do anything
# if the predicted value is correct
weightdiff <- eta * (y[ii] - ypred) * c(1,
as.numeric(x[ii, ]))
weight <- weight + weightdiff
# Update error function
if ((y[ii] - ypred) != 0) {
errors[jj] <- errors[jj] + 1
}
}
}
# weight to decide between the two species
return(errors)
}
err <- perceptron(x, y, 1, 10)
### my rewriting in functional form auxiliary
### function
faux <- function(x, weight, y, eta) {
err <- 0
z <- sum(weight[2:length(weight)] * as.numeric(x)) +
weight[1]
if (z < 0) {
ypred <- -1
} else {
ypred <- 1
}
# Change weight - the formula doesn't do anything
# if the predicted value is correct
weightdiff <- eta * (y - ypred) * c(1, as.numeric(x))
weight <<- weight + weightdiff
# Update error function
if ((y - ypred) != 0) {
err <- 1
}
err
}
weight <- rep(0, 3)
weightdiff <- rep(0, 3)
f <- function() {
t <- replicate(10, sum(unlist(lapply(seq_along(irissubdf$y),
function(i) {
faux(irissubdf[i, 1:2], weight, irissubdf$y[i],
1)
}))))
weight <<- rep(0, 3)
t
}
由于上述原因,我没想到会有任何持续的改进
问题。但是,当我看到急剧恶化时,我真的很惊讶
使用lapply 和replicate。
我使用 microbenchmark 库中的 microbenchmark 函数获得了这个结果
可能的原因是什么? 会不会是内存泄露?
expr min lq mean median uq
f() 48670.878 50600.7200 52767.6871 51746.2530 53541.2440
perceptron(as.matrix(irissubdf[1:2]), irissubdf$y, 1, 10) 4184.131 4437.2990 4686.7506 4532.6655 4751.4795
perceptronC(as.matrix(irissubdf[1:2]), irissubdf$y, 1, 10) 95.793 104.2045 123.7735 116.6065 140.5545
max neval
109715.673 100
6513.684 100
264.858 100
第一个函数是lapply/replicate函数
第二个是带有for循环的函数
第三个是C++中同样的函数使用Rcpp
这里根据 Roland 的功能剖析。 我不确定我能否以正确的方式解释它。 在我看来,大部分时间都花在子集上 Function profiling
【问题讨论】:
-
请准确。我在您的函数
f中没有看到对apply的任何调用。 -
我建议你学习如何分析函数:adv-r.had.co.nz/Profiling.html
-
您的代码中有几个错误;首先,
irissubdf[, 4] <- 1应该是irissubdf$y <- 1,所以以后可以使用该名称,其次,weight在f中使用之前没有定义。我也不清楚<<-在你的lapply和replicate命令中做正确的事情,但我不清楚它应该做什么。这也可能是两者之间的主要区别;<<-必须处理环境,而另一个则不需要,虽然我不知道这可能会产生什么影响,但它不再是苹果与苹果之间的比较了。 -
感谢指出,我只是忘记复制初始化权重(和权重差异)的代码。我使用了
-
嗨,我出于好奇尝试删除
标签: r performance lapply