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.
Vous pouvez utiliser pmap
pour une itération ligne par ligne. Les colonnes sont utilisées comme arguments de la fonction que vous utilisez. Dans votre exemple, vous auriez une fonction à trois arguments.
Par exemple, voici pmap
utilisant une fonction anonyme pour le travail que vous faites. Les colonnes sont transmises à la fonction dans l'ordre dans lequel elles se trouvent dans l'ensemble de données.
pmap(df, function(a, b, c) {
data.frame(var1 = a + b,
var2 = c/2)
} )
Vous pouvez utiliser le purrr tilde "short-hand" pour une fonction anonyme en vous référant aux colonnes dans l'ordre avec des nombres précédés de deux points.
pmap(df, ~data.frame(var1 = ..1 + ..2,
var2 = ..3/2) )
Si vous souhaitez obtenir ces résultats particuliers en tant que data.frame au lieu d'une liste, vous pouvez utiliser pmap_dfr
.
Notez que vous n'utilisez que des opérations vectorisées dans votre exemple, vous pouvez donc très bien 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 des fonctions non vectorisées telles que la médiane, vous pouvez utiliser pmap
comme dans la réponse de @aosmith, ou utiliser dplyr::rowwise
.
rowwise
est plus lent et les responsables du paquet conseillent d'utiliser la famille map
à la place, mais c'est sans doute plus agréable à l'œil que pmap
dans certains cas. Personnellement, je l'utilise toujours 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 sortie de liste sans nom stricte: res %>% split(seq(nrow(.))) %>% unname
)
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 map)
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