在R中通过colSums将列进行分割

33
我试图对矩阵中的值进行缩放,使得每一列加起来等于一。我尝试过以下方法:
m = matrix(c(1:9),nrow=3, ncol=3, byrow=T)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9

colSums(m)
12 15 18

m = m/colSums(m)
          [,1]      [,2] [,3]
[1,] 0.08333333 0.1666667 0.25
[2,] 0.26666667 0.3333333 0.40
[3,] 0.38888889 0.4444444 0.50

colSums(m)
[1] 0.7388889 0.9444444 1.1500000

显然这不起作用。 然后我尝试了这个:
m = m/matrix(rep(colSums(m),3), nrow=3, ncol=3, byrow=T)
          [,1]      [,2]      [,3]
[1,] 0.08333333 0.1333333 0.1666667
[2,] 0.33333333 0.3333333 0.3333333
[3,] 0.58333333 0.5333333 0.5000000

 m = colSums(m)
[1] 1 1 1

所以这个方法是可行的,但感觉好像还缺少些什么。这不可能是常规做法。我肯定是在这里犯了傻。 如果您能提供任何帮助,将不胜感激。 谢谢, Davy

3个回答

65
请查看?sweep,例如:
> sweep(m,2,colSums(m),`/`)
           [,1]      [,2]      [,3]
[1,] 0.08333333 0.1333333 0.1666667
[2,] 0.33333333 0.3333333 0.3333333
[3,] 0.58333333 0.5333333 0.5000000

你也可以转置矩阵,然后colSums(m)会被正确地循环使用。记得之后再次转置,像这样:

> t(t(m)/colSums(m))
           [,1]      [,2]      [,3]
[1,] 0.08333333 0.1333333 0.1666667
[2,] 0.33333333 0.3333333 0.3333333
[3,] 0.58333333 0.5333333 0.5000000

或者您可以使用函数prop.table()来实现基本相同的功能:

> prop.table(m,2)
           [,1]      [,2]      [,3]
[1,] 0.08333333 0.1333333 0.1666667
[2,] 0.33333333 0.3333333 0.3333333
[3,] 0.58333333 0.5333333 0.5000000

时间差别很小。 sweep() 函数和 t() 技巧是最灵活的解决方案,prop.table() 只适用于这种特殊情况。

8

像往常一样,Joris给出了一个很好的答案。我想到了另外两个:

#Essentially your answer
f1 <- function() m / rep(colSums(m), each = nrow(m))
#Two calls to transpose
f2 <- function() t(t(m) / colSums(m))
#Joris
f3 <- function() sweep(m,2,colSums(m),`/`)

Joris的答案在我的电脑上是最快的:

> m <- matrix(rnorm(1e7), ncol = 10000)
> library(rbenchmark)
> benchmark(f1,f2,f3, replications=1e5, order = "relative")
  test replications elapsed relative user.self sys.self user.child sys.child
3   f3       100000   0.386   1.0000     0.385    0.001          0         0
1   f1       100000   0.421   1.0907     0.382    0.002          0         0
2   f2       100000   0.465   1.2047     0.386    0.003          0         0

1
看起来你的帖子和我的编辑错过了。谢谢夸奖。 - Joris Meys
1
除非你正在处理大数据集,否则我喜欢sweep的表达能力...只是为了可爱,exp(scale(log(m),center=TRUE,scale=FALSE))怎么样(因为许多原因不是一个好主意!) - Ben Bolker
4
或者 scale(m, center=FALSE, scale=colSums(m))。该函数会对矩阵进行缩放,其中参数center为假表示不进行中心化,参数scale将应用到每一列并用列总和进行缩放。 - flodel

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接