2012-02-25 14 views
15

Próbuję przeskalować wartości w macierzy, tak aby każda kolumna sumowała się do jednej. Próbowałem:Dzielenie kolumn przez colSums w 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 

tak oczywiście to nie działa. Następnie próbowałem to:

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 

tak to działa, ale wydaje się, jakby mi czegoś brakuje tutaj. To nie może być sposób rutynowego wykonywania. Jestem pewien, że jestem tutaj głupi. Każda pomoc można dać byłoby mile widziane Wiwaty, Davy

Odpowiedz

38

Zobacz ?sweep, np:

> 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 

lub można transponować macierz a następnie colSums(m) zostaje poddane recyklingowi poprawnie. Nie zapomnij transpozycji potem znowu, tak:

> 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 

Albo użyć funkcji prop.table() zrobić w zasadzie taka sama:

> 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 

Różnice czasowe są raczej małe. funkcja sweep() i sztuczka t() są najbardziej elastycznymi rozwiązaniami, prop.table() jest tylko w tym szczególnym przypadku.

+0

genialny. Dziękuję Ci! Wstydzę się, że zupełnie zapomniałem o "prop.table()". –

5

Jak zwykle, Joris ma świetną odpowiedź. Dwa inne, które przyszło mi do głowy:

#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' odpowiedź jest najszybszy na moim komputerze:

> 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

Wygląda na to, że Twój wpis i moja edycja zostały przekazane. Thx za komplement. –

+0

, chyba że pracujesz nad ogromnym zestawem danych, lubię 'sweep' ze względu na jego wyrazistość ... po prostu dla słodkości, co powiesz na' exp (scale (log (m), center = TRUE, scale = FALSE)) '(nie jest to dobry pomysł z wielu powodów!) –

+3

lub 'scale (m, center = FALSE, scale = colSums (m))'. – flodel