如何加速以下(noob)代码:
#"mymatrix" is the matrix of word counts (docs X terms)
#"tfidfmatrix" is the transformed matrix
tfidfmatrix = Matrix(mymatrix, nrow=num_of_docs, ncol=num_of_words, sparse=T)
#Apply a transformation on each row of the matrix
for(i in 1:dim(mymatrix)[[1]]){
r = mymatrix[i,]
s = sapply(r, function(x) ifelse(x==0, 0, (1+log(x))*log((1+ndocs)/(1+x)) ) )
tfmat[i,] = s/sqrt(sum(s^2))
}
return (tfidfmatrix)
问题是我正在处理的矩阵相当大(~40kX100k),而且这段代码非常慢。
我没有使用“apply”(而不是使用for循环和sapply)的原因是apply会给我我想要的矩阵的转置 - 我想要num_of_docs X num_of_words,但是apply会给我转。然后,我将花费更多的时间来计算转置并重新分配它。
有关加快速度的想法吗?
非常感谢。
编辑:我发现下面的建议大大加快了我的代码(除了让我觉得愚蠢)。有关我可以从哪里学习编写“优化”R代码的建议吗?
编辑2:好的,所以事情不对。一旦我做s.vec[!is.finite(s.vec)] <- 0
s.vec的每个元素被设置为0.只是为了重新迭代我的原始矩阵是一个包含整数的稀疏矩阵。这是由于我正在使用的Matrix
包的一些怪癖。当我s.vec[which(s.vec==-Inf)] <- 0
事情按预期工作时。想法?
答案 0 :(得分:4)
根据我的评论,
#Slightly larger example data
mymatrix <- matrix(runif(10000),nrow=10)
mymatrix[sample(10000,100)] <- 0
tfmat <- matrix(nrow=10, ncol=1000)
ndocs <- 1
justin <- function(){
s.vec <- ifelse(mymatrix==0, 0, (1 + log(mymatrix)) * log((1 + ndocs)/(1 + mymatrix)))
tfmat.vec <- s.vec/sqrt(rowSums(s.vec^2))
}
joran <- function(){
s.vec <- (1 + log(mymatrix)) * log((1 + ndocs)/(1 + mymatrix))
s.vec[!is.finite(s.vec)] <- 0
tfmat.vec <- s.vec/sqrt(rowSums(s.vec^2))
}
require(rbenchmark)
benchmark(justin(),joran(),replications = 1000)
test replications elapsed relative user.self sys.self user.child sys.child
2 joran() 1000 0.940 1.00000 0.842 0.105 0 0
1 justin() 1000 2.786 2.96383 2.617 0.187 0 0
所以它大约快3倍左右。
答案 1 :(得分:3)
不确定ndocs
是什么,但ifelse
已经过矢量化,因此您应该能够使用ifelse
语句,而无需逐行遍历矩阵并sapply
沿着这条路。对于最终的计算也可以这样说。
但是,您还没有给出完整的复制示例...
mymatrix <- matrix(runif(100),nrow=10)
tfmat <- matrix(nrow=10, ncol=10)
ndocs <- 1
s.vec <- ifelse(mymatrix==0, 0, 1 + log(mymatrix)) * log((1 + ndocs)/(1 + mymatrix))
for(i in 1:dim(mymatrix)[[1]]){
r = mymatrix[i,]
s = sapply(r, function(x) ifelse(x==0, 0, (1+log(x))*log((1+ndocs)/(1+x)) ) )
tfmat[i,] <- s
}
all.equal(s.vec, tfmat)
所以唯一丢失的部分是最终计算中的rowSums
。
tfmat.vec <- s.vec/sqrt(rowSums(s.vec^2))
for(i in 1:dim(mymatrix)[[1]]){
r = mymatrix[i,]
s = sapply(r, function(x) ifelse(x==0, 0, (1+log(x))*log((1+ndocs)/(1+x)) ) )
tfmat[i,] = s/sqrt(sum(s^2))
}
all.equal(tfmat, tfmat.vec)