R:normalize(mean = 0,variance = 1)函数,可以与任意轴上的apply()一起使用

时间:2014-02-06 12:31:17

标签: r multidimensional-array normalization

我想要一个沿给定轴标准化数组的函数。基本上,我想写的是:

apply(X, axis, normalize)

它应该按行,列,......或沿着第n维标准化我的数组。

这听起来像是一个非常普遍的问题,但R似乎无法在不使用怪癖的情况下解决它。

考虑以下矩阵和函数:

> m = matrix(1:4,nrow=2,dimnames=list(c('a','b'),c('x','y')))
> m
  x y
a 1 3
b 2 4

normalize=function(X) {
    X = X - mean(X)
    X = X/sd(X)
    return(X)
}

如果我使用带有轴编号的apply(),则会出现以下情况:

> apply(m, 2, normalize)
           x          y
a -0.7071068 -0.7071068
b  0.7071068  0.7071068

这里一切都很好

> apply(m, 1, normalize)
           a          b
x -0.7071068 -0.7071068
y  0.7071068  0.7071068

这里,矩阵已被转置(这是我不想要的)。我想保留n维数组的原始尺寸。

工作的可能答案是:

  • 使用t(),跨行应用它然后转置回来:这不适用于多维数组
  • 使用 y 包的函数 x :可能与上面相同
  • 为每个维度编写if子句:解决方案通常适用,不仅适用于某些硬编码案例

编辑:根据Roland的建议,我将使用以下函数代替apply

array_apply = function(X, along, FUN) {
    X = as.array(X)
    ndim = c(1:length(dim(X)))

    preserveAxes = ndim[ndim != along]
    orderAxes = c(along, preserveAxes)

    X = apply(X, preserveAxes, FUN)
    return(aperm(X, orderAxes))
}

的行为方式如下:

> m = matrix(1:4,nrow=2,dimnames=list(c('a','b'),c('x','y')))

> array_apply(m,1,normalize)
       x          y
a -0.7071068 -0.7071068
b  0.7071068  0.7071068

> array_apply(m,2,normalize)
       x         y
a -0.7071068 0.7071068
b -0.7071068 0.7071068

1 个答案:

答案 0 :(得分:3)

让我们用一个更好的例子来看看会发生什么:

m = matrix(c(1,2,7,10,12,18),nrow=2)
#     [,1] [,2] [,3]
#[1,]    1    7   12
#[2,]    2   10   18
apply(m, 1, scale)
#            [,1] [,2]
#[1,] -1.02888681   -1
#[2,]  0.06052275    0
#[3,]  0.96836405    1

如您所见,scale应用于矩阵行,结果向量组合为结果矩阵的列。

apply(m, 2, scale)
#           [,1]       [,2]       [,3]
#[1,] -0.7071068 -0.7071068 -0.7071068
#[2,]  0.7071068  0.7071068  0.7071068

现在scale应用于矩阵列,但结果向量再次组合为结果矩阵的列。事实上,help("apply")

记录了这一点
  

如果每次调用FUN都返回一个长度为n的向量,则apply返回   如果n> 1,则为维数c(n,dim(X)[MARGIN])的数组。 1。

修改:

如果您执行以下操作,则可以避免此问题:

(m-apply(m,1,mean))/apply(m,1,sd)
          [,1]       [,2]      [,3]
[1,] -1.028887 0.06052275 0.9683641
[2,] -1.000000 0.00000000 1.0000000