2

我有一个大矩阵(数千行和数百行),我想在 -1 和 1 之间按列标准化。这是我写的代码:

normalize <- function(x) { 
    for(j in 1:length(x[1,])){
        print(j)
        min <- min(x[,j])
        max <- max(x[,j])
        for(i in 1:length(x[,j])){
            x[i,j] <- 2 * (x[i,j] - min)/( max - min) - 1
        }
    }
    return(x)
}

不幸的是,它变慢了。我看过这个:

normalize <- function(x) { 
    x <- sweep(x, 2, apply(x, 2, min)) 
    sweep(x, 2, apply(x, 2, max), "/") 
}

它很快,但它在 0 和 1 之间正常化。你能帮我修改一下吗?对不起,我刚开始学习 R

4

4 回答 4

4

x在你自己的函数结束时重新调整矩阵怎么样?

normalize <- function(x) { 
    x <- sweep(x, 2, apply(x, 2, min)) 
    x <- sweep(x, 2, apply(x, 2, max), "/") 
    2*x - 1
}
于 2013-01-11T16:37:14.787 回答
4

基准:

normalize2 <- function(A) { 
  scale(A,center=TRUE,scale=apply(A,2,function(x) 0.5*(max(x)-min(x))))
}

normalize3 <- function(mat) { 
  apply(mat,2,function(x) {xmin <- min(x); 2*(x-xmin)/(max(x)-xmin)-1})
}

normalize4 <- function(x) { 
  aa <- colMeans(x)
  x <- sweep(x, 2, aa)           # retrive the mean from each column

  2* sweep(x, 2, apply(x, 2, function(y) max(y)-min(y)), "/") 
}


set.seed(42)
mat <- matrix(sample(1:10,1e5,TRUE),1e3)
erg2 <- normalize2(mat)
attributes(erg2) <- attributes(normalize3(mat))
all.equal(  
  erg2,  
  normalize3(mat),   
  normalize4(mat)
  )

[1] TRUE

library(microbenchmark)
microbenchmark(normalize4(mat),normalize3(mat),normalize2(mat))

Unit: milliseconds
             expr      min       lq   median       uq      max
1 normalize2(mat) 4.846551 5.486845 5.597799 5.861976 30.46634
2 normalize3(mat) 4.191677 4.862655 4.980571 5.153438 28.94257
3 normalize4(mat) 4.960790 5.648666 5.766207 5.972404 30.08334

set.seed(42)
mat <- matrix(sample(1:10,1e4,TRUE),10)
microbenchmark(normalize4(mat),normalize3(mat),normalize2(mat))

Unit: milliseconds
             expr      min       lq   median       uq       max
1 normalize2(mat) 4.319131 4.445384 4.556756 4.821512  9.116263
2 normalize3(mat) 5.743305 5.927829 6.098392 6.454875 13.439526
3 normalize4(mat) 3.955712 4.102306 4.175394 4.402710  5.773221

如果列apply数较少,解决方案会稍微慢一些,但如果列数很大,则解决方案会稍微快一些。总体而言,性能是相同的数量级。

于 2013-01-11T17:35:47.893 回答
2

这将使用相同的方法重新调整矩阵

normalize <- function(x) { 
  x <- sweep(x, 2, apply(x, 2, mean))           # retrive the mean from each column
  2* sweep(x, 2, apply(x, 2, function(y) max(y)-min(y)), "/") 
}

}

编辑

按照评论中的建议使用colMeans当然更快

normalize <- function(x) { 
  aa <- colMeans(x)
  x <- sweep(x, 2, aa)           # retrive the mean from each column

  2* sweep(x, 2, apply(x, 2, function(y) max(y)-min(y)), "/") 
}
A <- matrix(1:24, ncol=3)

> normalize(A)
           [,1]       [,2]       [,3]
[1,] -1.0000000 -1.0000000 -1.0000000
[2,] -0.7142857 -0.7142857 -0.7142857
[3,] -0.4285714 -0.4285714 -0.4285714
[4,] -0.1428571 -0.1428571 -0.1428571
[5,]  0.1428571  0.1428571  0.1428571
[6,]  0.4285714  0.4285714  0.4285714
[7,]  0.7142857  0.7142857  0.7142857
[8,]  1.0000000  1.0000000  1.0000000

scale使用基础包的功能进行编辑

scale(A,center=TRUE,scale=apply(A,2,function(x) 0.5*(max(x)-min(x))))
           [,1]       [,2]       [,3]
[1,] -1.0000000 -1.0000000 -1.0000000
[2,] -0.7142857 -0.7142857 -0.7142857
[3,] -0.4285714 -0.4285714 -0.4285714
[4,] -0.1428571 -0.1428571 -0.1428571
[5,]  0.1428571  0.1428571  0.1428571
[6,]  0.4285714  0.4285714  0.4285714
[7,]  0.7142857  0.7142857  0.7142857
[8,]  1.0000000  1.0000000  1.0000000
于 2013-01-11T16:39:43.320 回答
1

怎么样:

x[,1] <- (x[,1]-mean(x[,1]))/(max(x[,1])-min(x[,1]))

中的大多数基本函数R都是矢量化的,因此无需for在代码中包含循环。此代码段将缩放第 1 列的所有内容(您也可以使用该函数scale(),尽管它没有最小/最大值选项)。

要创建整个数据集,您可以执行以下操作:

Scale <- function(y) y <- (y-mean(y))/(max(y)-min(y))
DataFrame.Scaled <- apply(DataFrame, 2, Scale)

编辑:还值得指出的是,您不想在函数之后命名值。当你这样做时min <- min(x),它会在你下次请求时给 R 带来一些混乱min

于 2013-01-11T16:30:40.677 回答