2012-02-25 43 views
15

Estoy intentando escalar los valores en una matriz para que cada columna sume uno. Lo he intentado:División de columnas por columnas en 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 

obviamente esto no funciona. entonces he intentado esto:

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 

por lo que este funciona, pero se siente como que estoy perdiendo algo. Esto no puede ser como se hace rutinariamente. Estoy seguro de que estoy siendo estúpido aquí. Cualquier ayuda que puede dar sería apreciada Saludos, Davy

Respuesta

38

Ver ?sweep, por ejemplo:

> 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 

o puede transponer la matriz y luego colSums(m) se recicla correctamente. No se olvide de incorporar posteriormente de nuevo, como esto:

> 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 se utiliza la función prop.table() hacer básicamente lo mismo:

> 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 

Las diferencias de tiempo son bastante pequeñas. la función sweep() y el truco t() son las soluciones más flexibles, prop.table() es solo para este caso particular

+0

brillante. ¡Gracias! Avergonzado por haberme olvidado por completo de 'prop.table()'. –

5

Por lo general, Joris tiene una gran respuesta. Otras dos personas que vienen a la 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),`/`) 

respuesta Joris' es el más rápido en mi máquina:

> 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

Parece que su publicación y mi edición pasaron entre ellos. Gracias por el cumplido. –

+0

a menos que esté trabajando en un gran conjunto de datos, me gusta 'sweep' por su expresividad ... solo por ternura, ¿qué tal' exp (scale (log (m), center = TRUE, scale = FALSE)) '(¡no es una buena idea por muchas razones!) –

+3

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

Cuestiones relacionadas