2012-02-25 52 views
15

我想縮放矩陣中的值,以便每列加起來一個。我曾嘗試過:用colSums在R中劃分列

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 

所以這個工作,但感覺就像我失去了一些東西。這不可能是常規做法。我確定我在這裏很愚蠢。 任何幫助您能給將不勝感激 乾杯, 戴維

回答

38

?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()只適用於這種特殊情況

+0

輝煌。謝謝!慚愧我完全忘了'prop.table()'。 – 2012-02-25 23:19:33

5

平時,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),`/`) 

里斯的回答是最快的在我的機器上:

> 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

似乎像你的文章,我的編輯傳遞給彼此。 Thx恭維。 – 2012-02-25 21:09:59

+0

除非你正在處理一個龐大的數據集,我喜歡'sweep'的表現力......只是爲了可愛,'exp(scale(log(m),center = TRUE,scale = FALSE)'(由於很多原因,不是一個好主意!) – 2012-02-25 21:45:01

+3

或'scale(m,center = FALSE,scale = colSums(m))'。 – flodel 2012-02-25 22:53:40