60 votes

Itération en ligne comme appliquer avec purrr

Comment réaliser une itération ligne par ligne en utilisant purrr :: map?

Voici comment je le ferais avec une application standard par ligne.

 df <- data.frame(a = 1:10, b = 11:20, c = 21:30)

lst_result <- apply(df, 1, function(x){
            var1 <- (x[['a']] + x[['b']])
            var2 <- x[['c']]/2
            return(data.frame(var1 = var1, var2 = var2))
          })
 

Cependant, ce n'est pas trop élégant, et je préfère le faire avec du ronronnement. Peut (ou non) être plus rapide aussi.

71voto

aosmith Points 19444

Vous pouvez utiliser pmap pour la ligne sage itération. Les colonnes sont utilisées comme arguments de quelle que soit la fonction que vous utilisez. Dans votre exemple, vous avez un trois-argument de la fonction.

Par exemple, ici, est - pmap à l'aide d'une fonction anonyme pour le travail que vous faites. Les colonnes sont transmis à la fonction dans l'ordre qu'ils sont dans le jeu de données.

pmap(df, function(a, b, c) {
     data.frame(var1 = a + b,
                var2 = c/2) 
     }  ) 

Vous pouvez utiliser le purrr tilde "à court de main" pour une fonction anonyme en se référant aux colonnes dans l'ordre avec les nombres précédés par deux points.

pmap(df, ~data.frame(var1 = ..1 + ..2,
                var2 = ..3/2)  ) 

Si vous souhaitez obtenir ces résultats en tant que données.cadre au lieu d'une liste, vous pouvez utiliser pmap_dfr.

10voto

Moody_Mudskipper Points 18115

Notez que vous êtes en utilisant uniquement vectorisé opérations dans votre exemple, de sorte que vous pourriez très bien le faire :

df %>% dplyr::transmute(var1 = a+b,var2 = c/2)

(ou en base R: transform(df,var1 = a+b,var2 = c/2)[4:5])

Si vous utilisez non vectorisé fonctions telles que la médiane vous pouvez utiliser pmap comme dans @aosmith 's réponse, ou de l'utilisation dplyr::rowwise.

rowwise est plus lente et les mainteneurs de paquets vous conseille d'utiliser le map de la famille au lieu de cela, mais il est sans doute plus facile sur les yeux qu' pmap dans certains cas. Personnellement, j'ai toujours l'utiliser lorsque la vitesse n'est pas un problème:

library(dplyr)
df %>% transmute(var3 = pmap(.,~median(c(..1,..2,..3))))
df %>% rowwise %>% transmute(var3 = median(c(a,b,c)))

(pour revenir à une stricte sans nom de la liste de sortie : res %>% split(seq(nrow(.))) %>% unname)

6voto

Andre Elrico Points 5210

Vous êtes libre de toujours créer un wrapper autour d'une fonction que vous "aimez".

 rmap <- function (.x, .f, ...) {
    if(is.null(dim(.x))) stop("dim(X) must have a positive length")
    .x <- t(.x) %>% as.data.frame(.,stringsAsFactors=F)
    purrr::map(.x=.x,.f=.f,...)
}
 

appliquer la nouvelle fonction rmap (r owwise carte)

 rmap(df1,~{
    var1 <- (.x[[1]] + .x[[2]])
    var2 <- .x[[3]]/2
    return(data.frame(var1 = var1, var2 = var2))
    })
 

Informations supplémentaires: (eval de haut en bas)

 df1 <- data.frame(a=1:3,b=1:3,c=1:3)
m   <- matrix(1:9,ncol=3)

apply(df1,1,sum)
rmap(df1,sum)

apply(m,1,sum)
rmap(m,sum)

apply(1:10,1,sum)  # intentionally throws an error
rmap(1:10,sum)     # intentionally throws an error
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X