我想要一个大矩阵,我想把它放在中心位置:
X <- matrix(sample(1:10, 5e+08, replace=TRUE), ncol=10000)
使用colMeans快速有效地找到方法:
means <- colMeans(X)
但是从每列中减去相应均值的方法是什么(快速且内存效率高)?这有效,但感觉不对:
for (i in 1:length(means)){
X[,i] <- X[,i]-means[i]
}
有更好的方法吗?
/ edit:这是对DWin编写的各种基准测试的更改,包括其他发布的建议:
require(rbenchmark)
X <- matrix(sample(1:10, 5e+07, replace=TRUE), ncol=10000)
frlp.c <- compiler:::cmpfun(function(mat){
means <- colMeans(mat)
for (i in 1:length(means)){
mat[,i] <- mat[,i]-means[i]
}
return(mat)
})
mat.c <- compiler:::cmpfun(function(mat){
t(t(X) - colMeans(X))
})
swp.c <- compiler:::cmpfun(function(mat){
sweep(mat, 2, colMeans(mat), FUN='-')
})
scl.c <- compiler:::cmpfun(function(mat){
scale(mat, scale=FALSE)
})
matmult.c <- compiler:::cmpfun(function(mat){
mat-rep(1, nrow(mat)) %*% t(colMeans(mat))
})
benchmark(
frlp.c=frlp.c(X),
mat=mat.c(X),
swp=swp.c(X),
scl=scl.c(X),
matmult=matmult.c(X),
replications=10,
order=c('replications', 'elapsed'))
matmult功能似乎是新的赢家!我真的想在5e + 08元素矩阵上尝试这些,但是我的内存不足。
test replications elapsed relative user.self sys.self user.child sys.child
5 matmult 10 11.98 1.000 7.47 4.47 NA NA
1 frlp.c 10 35.05 2.926 31.66 3.32 NA NA
2 mat 10 50.56 4.220 44.52 5.67 NA NA
4 scl 10 58.86 4.913 50.26 8.42 NA NA
3 swp 10 61.25 5.113 51.98 8.64 NA NA
答案 0 :(得分:6)
这对你有用吗?
sweep(X, 2, colMeans(X)) # this substracts the colMean to each col
scale(X, center=TRUE, scale=FALSE) # the same
sweep(X, 2, colMeans(X), FUN='/') # this makes division
如果您想根据for
循环加快代码速度,可以使用cmpfun
包中的compiler
。实施例
X <- matrix(sample(1:10, 500000, replace=TRUE), ncol=100) # some data
means <- colMeans(X) # col means
library(compiler)
# One of your functions to be compiled and tested
Mean <- function(x) {
for (i in 1:length(means)){
X[,i] <- X[,i]-means[i]
}
return(X)
}
CMean <- cmpfun(Mean) # compiling the Mean function
system.time(Mean(X))
user system elapsed
0.028 0.016 0.101
system.time(CMean(X))
user system elapsed
0.028 0.012 0.066
也许这个建议可以帮到你。
答案 1 :(得分:6)
这似乎是sweep()
的两倍。
X - rep(1, nrow(X)) %*% t(colMeans(X))
X <- matrix(sample(1:10, 5e+06, replace=TRUE), ncol=10000)
system.time(sweep(X, 2, colMeans(X)))
user system elapsed
0.33 0.00 0.33
system.time(X - rep(1, nrow(X)) %*% t(colMeans(X)))
user system elapsed
0.15 0.03 0.19
DWin编辑:当我使用比使用的OP更小的矩阵(仅5e + 07)时,我得到了这些时间,其中Josh是mat2(较大的一个溢出到我的Mac上的虚拟内存,32GB并且需要被终止):
test replications elapsed relative user.self sys.self user.child sys.child
2 mat2 1 0.546 1.000000 0.287 0.262 0 0
3 mat 1 2.372 4.344322 1.569 0.812 0 0
1 frlp 1 2.520 4.615385 1.720 0.809 0 0
4 swp 1 2.990 5.476190 1.959 1.043 0 0
5 scl 1 3.019 5.529304 1.984 1.046 0 0
答案 2 :(得分:3)
我可以看出为什么Jilber不确定你想要什么,因为有一点你要求分裂,但在你的代码中你使用减法。他建议的扫描操作在这里是多余的。只需使用比例就可以了:
cX <- scale(X, scale=FALSE) # does the centering with subtraction of col-means
sX <- scale(X, center=FALSE) # does the scaling operation
csX <- scale(X) # does both
(很难相信scale
更慢。看看它的代码。在列上使用sweep
scale.default # since it's visible.
矩阵方法:
t( t(X) / colMeans(X) )
编辑:一些时间安排(我错误地认为scale
等同于sweep-colMeans):
require(rbenchmark)
benchmark(
mat={sX <- t( t(X) / colMeans(X) ) },
swp ={swX <- sweep(X, 2, colMeans(X), FUN='/')},
scl={sX <- scale(X, center=FALSE)},
replications=10^2,
order=c('replications', 'elapsed'))
#-----------
test replications elapsed relative user.self sys.self user.child sys.child
1 mat 100 0.015 1.000000 0.015 0 0 0
2 swp 100 0.015 1.000000 0.015 0 0 0
3 scl 100 0.025 1.666667 0.025 0 0 0
当你加油时会发生一些有趣的事情。上面的标志对samall矩阵-X很生气。以下是与您使用的更接近的内容:
benchmark(
frlp ={means <- colMeans(X)
for (i in 1:length(means)){
X[,i] <- X[,i]-means[i]
}
},
mat={sX <- t( t(X) - colMeans(X) ) },
swp ={swX <- sweep(X, 2, colMeans(X), FUN='-')},
scl={sX <- scale(X, scale=FALSE)},
replications=10^2,
order=c('replications', 'elapsed'))
#
test replications elapsed relative user.self sys.self user.child sys.child
2 mat 100 2.075 1.000000 1.262 0.820 0 0
3 swp 100 2.964 1.428434 1.917 1.058 0 0
4 scl 100 2.981 1.436627 1.935 1.059 0 0
1 frlp 100 3.651 1.759518 2.540 1.128 0 0
答案 3 :(得分:3)
也许编译你的frlp()
函数会加快一些速度?
frlp.c <- compiler:::cmpfun(function(mat){
means <- colMeans(mat)
for (i in 1:length(means)){
mat[,i] <- mat[,i]-means[i]
}
mat
}
)
[编辑]:对我而言,它并没有加快速度,但我必须大幅缩小X
才能在我的电脑上工作。它可能很好地扩展,不知道
您可能还希望与JIT进行比较:
frlp.JIT <- function(mat){
means <- colMeans(mat)
compiler::enableJIT(2)
for (i in 1:length(means)){
mat[,i] <- mat[,i]-means[i]
}
mat
}
答案 4 :(得分:1)
这里还有一些,没有像乔希那样快:
X <- matrix(runif(1e6), ncol = 1000)
matmult <- function(mat) mat - rep(1, nrow(mat)) %*% t(colMeans(mat))
contender1 <- function(mat) mat - colMeans(mat)[col(mat)]
contender2 <- function(mat) t(apply(mat, 1, `-`, colMeans(mat)))
contender3 <- function(mat) mat - rep(colMeans(mat), each = nrow(mat))
contender4 <- function(mat) mat - matrix(colMeans(mat), nrow(mat), ncol(mat),
byrow = TRUE)
benchmark(matmult(X),
contender1(X),
contender2(X),
contender3(X),
contender4(X),
replications = 100,
order=c('replications', 'elapsed'))
# test replications elapsed relative user.self sys.self
# 1 matmult(X) 100 1.41 1.000000 1.39 0.00
# 5 contender4(X) 100 1.90 1.347518 1.90 0.00
# 4 contender3(X) 100 2.69 1.907801 2.69 0.00
# 2 contender1(X) 100 2.74 1.943262 2.73 0.00
# 3 contender2(X) 100 6.30 4.468085 6.26 0.03
请注意,我正在测试一个数字矩阵,而不是整数;我想更多人会觉得有用(如果它有所不同。)