r mapply

Aplicar una función sobre todas las combinaciones de argumentos.



mapply (1)

Me gustaría poder aplicar una función a todas las combinaciones de un conjunto de argumentos de entrada. Tengo una solución de trabajo (a continuación) pero me sorprendería si no hubiera una forma mejor / más genérica de hacerlo, por ejemplo, plyr, pero hasta ahora no he encontrado nada. ¿Hay una solución mejor?

# Apply function FUN to all combinations of arguments and append results to # data frame of arguments cmapply <- function(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) { l <- expand.grid(..., stringsAsFactors=FALSE) r <- do.call(mapply, c( list(FUN=FUN, MoreArgs = MoreArgs, SIMPLIFY = SIMPLIFY, USE.NAMES = USE.NAMES), l )) if (is.matrix(r)) r <- t(r) cbind(l, r) }

ejemplos:

# calculate sum of combinations of 1:3, 1:3 and 1:2 cmapply(arg1=1:3, arg2=1:3, 1:2, FUN=sum) # paste input arguments cmapply(arg1=1:3, arg2=c("a", "b"), c("x", "y", "z"), FUN=paste) # function returns a vector cmapply(a=1:3, b=2, FUN=function(a, b) c("x"=b-a, "y"=a+b))


Esta función no es necesariamente mejor, solo ligeramente diferente:

rcapply <- function(FUN, ...) { ## Cross-join all vectors DT <- CJ(...) ## Get the original names nl <- names(list(...)) ## Make names, if all are missing if(length(nl)==0L) nl <- make.names(1:length(list(...))) ## Fill in any missing names nl[!nzchar(nl)] <- paste0("arg", 1:length(nl))[!nzchar(nl)] setnames(DT, nl) ## Call the function using all columns of every row DT2 <- DT[, as.data.table(as.list(do.call(FUN, .SD))), ## Use all columns... by=.(rn=1:nrow(DT))][ ## ...by every row , rn:=NULL] ## Remove the temp row number ## Add res to names of unnamed result columns setnames(DT2, gsub("(V)([0-9]+)", "res//2", names(DT2))) return(data.table(DT, DT2)) } head(rcapply(arg1=1:3, arg2=1:3, 1:2, FUN=sum)) ## arg1 arg2 arg3 res1 ## 1: 1 1 1 3 ## 2: 1 1 2 4 ## 3: 1 2 1 4 ## 4: 1 2 2 5 ## 5: 1 3 1 5 ## 6: 1 3 2 6 head(rcapply(arg1=1:3, arg2=c("a", "b"), c("x", "y", "z"), FUN=paste)) ## arg1 arg2 arg3 res1 ## 1: 1 a x 1 a x ## 2: 1 a y 1 a y ## 3: 1 a z 1 a z ## 4: 1 b x 1 b x ## 5: 1 b y 1 b y ## 6: 1 b z 1 b z head(rcapply(a=1:3, b=2, FUN=function(a, b) c("x"=b-a, "y"=a+b))) ## a b x y ## 1: 1 2 1 3 ## 2: 2 2 0 4 ## 3: 3 2 -1 5