2012-02-25 14 views
15

Sto provando a scalare i valori in una matrice in modo che ogni colonna ne sommi uno. Ho provato:Divisione colonne per colSum in 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 

quindi ovviamente questo non funziona. Allora ho provato questo:

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 

così questo funziona, ma ci si sente come mi manca qualcosa qui. Questo non può essere come è fatto abitualmente. Sono sicuro di essere stupido qui. Qualsiasi aiuto che potete dare sarebbe apprezzato Cheers, Davy

risposta

38

Vedi ?sweep, ad esempio:

> 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 

oppure è possibile trasporre la matrice e poi colSums(m) ottiene riciclato correttamente. Non dimenticare di trasporre poi di nuovo, in questo modo:

> 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 

O si utilizza la funzione prop.table() di fare fondamentalmente la stessa:

> 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 

Le differenze di tempo sono piuttosto piccole. la funzione sweep() e il trucco t() sono le soluzioni più flessibili, prop.table() è solo per questo caso specifico

+0

brillante. Grazie! Mi vergogno del fatto che ho completamente dimenticato 'prop.table()'. –

5

Come al solito, Joris ha un'ottima risposta. Due altri che mi venivano in mente:

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

risposta Joris' è il più veloce sulla mia macchina:

> 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

Sembra il tuo post e la mia modifica passata a vicenda. Grazie per il complimento. –

+0

a meno che non si stia lavorando su un enorme set di dati, mi piace 'sweep' per la sua espressività ... solo per carineria, che dire di exp (scala (log (m), center = TRUE, scale = FALSE))' (non è una buona idea per molte ragioni!) –

+3

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