2011-01-21 10 views
11

tengo una lista de funciones¿Aplica una lista de n funciones a cada fila de un marco de datos?

funs <- list(fn1 = function(x) x^2, 
      fn2 = function(x) x^3,    
      fn3 = function(x) sin(x), 
      fn4 = function(x) x+1) 
#in reality these are all f = splinefun() 

Y tengo una trama de datos:

mydata <- data.frame(x1 = c(1, 2, 3, 2), 
        x2 = c(3, 2, 1, 0), 
        x3 = c(1, 2, 2, 3), 
        x4 = c(1, 2, 1, 2)) 
#actually a 500x15 dataframe of 500 samples from 15 parameters 

Para cada uno de i filas, me gustaría función de evaluar j en cada uno de los j columnas y sumar los resultados:

unlist(funs) 
attach(mydata) 
a <- rep(NA,4) 
for (i in 1:4) { 
    a[i] <- sum(fn1(x1[i]), fn2(x2[i]), fn3(x3[i]), fn4(x4[i])) 
} 

¿Cómo puedo hacer esto de manera eficiente? ¿Es esta una ocasión apropiada para implementar las funciones plyr? ¿Si es así, cómo?

pregunta de bonificación: ¿por qué es a[4]NA?

¿Es este un momento apropiado para usar las funciones de plyr, de ser así, cómo puedo hacerlo?

+1

@abe para el tercer fragmento de código, necesita 'unlist (funs)' y 'attach (mydata)' o usar 'funs $ fn1' y' mydata $ x1' –

+0

@David gracias por la corrección, I han cambiado el código para reflejar esto, pero este es exactamente el desorden que me gustaría evitar. – Abe

+2

Bueno, para el punto de bonificación, la respuesta es que no hay 4º elemento en mydata $ x4 ni ninguna de las columnas de ese marco de datos. Un comentario adicional ... simplemente escribiendo unlist (funs) no hace nada a menos que asigne el resultado a algo. Bienvenido a la programación funcional. –

Respuesta

9

Ignorando el fragmento de código y ajustarse a su especificación inicial que desea aplicar la función j en el número de columna j y luego "sumar los resultados" ... que puede hacer:

mapply(do.call, funs, lapply(mydata, list)) 
#  [,1] [,2]  [,3] [,4] 
# [1,] 1 27 0.8414710 2 
# [2,] 4 8 0.9092974 3 
# [3,] 9 1 0.9092974 3 

No estaba seguro de qué manera desea ahora agregar los resultados (es decir, por filas o columna), por lo que podría hacer rowSums o colSums en esta matriz. E.g .:

colSums(mapply(do.call, funs, lapply(mydata, list))) 
# [1] 14.000000 36.000000 2.660066 8.000000 
+0

gracias por esta ayuda; Usaré rowSums pero este es el concepto que estaba buscando. – Abe

+0

No entiendo lo que hace la última lista, ¿no es el segundo argumento para hacer. Llamar una lista de argumentos a la función? – Abe

+0

He editado la segunda expresión anterior ligeramente (no es necesario hacer 'as.list'). Necesitas hacer 'lapply (mydata, list)' para convertir 'mydata' en una lista de listas. Luego el 'mapply' hace que' do.call' tome cada función en 'funs', y toma el miembro de la lista correspondiente de' lapply (mydata, list) ', que a su vez es una lista. –

4

¿Por qué no solo escribe una función para las 4 y la aplica al marco de datos? Todas sus funciones están vectorizados, y también lo es splinefun, siendo este punto:

fun <- function(df) 
    cbind(df[, 1]^2, df[, 2]^3, sin(df[, 3]), df[, 4] + 1) 

rowSums(fun(mydata)) 

Esto es considerablemente más eficiente que "foring" o "aplicar" sobre las filas.

0

He intentado utilizar plyr::each:

library(plyr) 
sapply(mydata, each(min, max)) 
    x1 x2 x3 x4 
min 1 0 1 1 
max 3 3 3 2 

y trabaja muy bien, pero cuando paso funciones personalizadas consigo:

sapply(mydata, each(fn1, fn2)) 
Error in proto[[i]] <- fs[[i]](x, ...) : 
    more elements supplied than there are to replace 

each tiene muy breve documentación, yo no lo entiendo muy bien lo que es el problema.

Cuestiones relacionadas