2011-02-16 42 views
5

¿Cuál es la forma programática de operar en múltiples columnas (o filas) a la vez? Considere el ejemplo:Operar en varias columnas a la vez

df2 <- data.frame(a = 1:10, b = 5:14, c = 10:1, d = 14:5) 

me gustaría crear dos nuevas columnas que contienen la relación de a/d b y c /. Por simplicidad, supongamos que la relación espacial entre todas las columnas es consistente. Con sólo dos columnas que hacen, se podría también hacer algo como esto:

df2$ab <- with(df2, a/b) 
df2$cd <- with(df2, c/d) 

o

df2 <- transform(df2, ab = a/b, cd = c/d) 

para crear un producto final como:

a b c d  ab  cd 
1 1 5 10 14 0.2000000 0.7142857 
2 2 6 9 13 0.3333333 0.6923077 
3 3 7 8 12 0.4285714 0.6666667 
4 4 8 7 11 0.5000000 0.6363636 
5 5 9 6 10 0.5555556 0.6000000 
6 6 10 5 9 0.6000000 0.5555556 
7 7 11 4 8 0.6363636 0.5000000 
8 8 12 3 7 0.6666667 0.4285714 
9 9 13 2 6 0.6923077 0.3333333 
10 10 14 1 5 0.7142857 0.2000000 

Pero lo que si hay ¿Cientos de columnas que necesita para iterar? Normalmente usaría Excel o SQL para concatenar el código y soltarlo en mi script .R, pero parece que debe haber una manera de resolverlo con R.

Divulgación completa: esta pregunta está relacionada con una pregunta sobre cross validated donde pirateé una solución que no puede ser óptima.

Respuesta

4

Pruebe esta solución:

df2 <- data.frame(a = 1:10, b = 5:14, c = 10:1, d = 14:5, e = 34:43, f = 56:65) 

n <- ncol(df2) 
s1 <- seq(1, n, 2) 
s2 <- seq(2, n, 2) 

df2[paste(names(df2)[s1], names(df2)[s2], sep="")] <- df2[, s1]/df2[, s2] 
+0

su solución editado @ de djhurio es casi equivalente a la de bucle para Vine arriba con. También actualizaré las pruebas de rendimiento más tarde. ¡Gracias! 'cbind'ing el objeto de resultado a sí mismo demostrará ser más lento que su nueva solución. – Chase

0

¿Qué hay de esta solución? Evita cbind ing del objeto a sí mismo varias veces:

for (i in seq(1, ncol(df2), by = 2)) { 
    df2[, paste(names(df2)[i], names(df2)[i+1], sep = "", collapse = "")] <- df2[, i]/df2[, i + 1] 
} 

EDIT: Parece que mi solución es marginalmente más rápido que

> set.seed(42) 
> df2 <- data.frame(
+  a = sample(1:10, 10e6, T) 
+ , b = sample(1:10, 10e6, T) 
+ , c = sample(1:10, 10e6, T) 
+ , d = sample(1:10, 10e6, T) 
+) 
> 
> system.time(
+ for (i in seq(1, ncol(df2), by = 2)) { 
+ df2[, paste(names(df2)[i], names(df2)[i+1], sep = "", collapse = "")] <- df2[, i]/df2[, i + 1] 
+ } 
+) 
    user system elapsed 
    1.06 0.64 1.70 
> 
> foo <- function(df2) { 
+ n <- ncol(df2) 
+ s1 <- seq(1, n, 2) 
+ s2 <- seq(2, n, 2) 
+ df2 <- cbind(df2, df2[, s1]/df2[, s2]) 
+ names(df2)[(n+1):ncol(df2)] <- paste(names(df2)[s1], names(df2)[s2], sep="") 
+ return(df2) 
+ } 
> 
> set.seed(42) 
> df2 <- data.frame(
+  a = sample(1:10, 10e6, T) 
+ , b = sample(1:10, 10e6, T) 
+ , c = sample(1:10, 10e6, T) 
+ , d = sample(1:10, 10e6, T) 
+) 
> system.time(foo(df2)) 
    user system elapsed 
    1.73 0.85 2.57