J'ai une donnée:
Source: local data frame [30 x 5]
Groups: <by row>
# A tibble: 30 x 5
x.1 x.2 x.3 x.4 var
<dbl> <dbl> <dbl> <dbl> <dbl>
1 32.7 42.7 50.1 20.8 7091.
2 75.9 71.3 83.6 77.6 7091.
3 49.6 28.7 97.0 59.7 7091.
4 47.4 96.1 31.9 79.7 7091.
5 54.2 47.1 81.7 41.6 7091.
6 27.9 58.1 97.4 25.9 7091.
7 61.8 78.3 52.6 67.7 7091.
8 85.4 51.3 38.8 82.0 7091.
9 27.9 72.6 68.9 25.2 7091.
10 87.2 42.1 27.6 73.9 7091.
# ... with 20 more rows
La fonction suivante fonctionne:
df_1 %>% select(-y) %>% rowwise() %>% mutate(var = sum(select_if(., is.numeric)))
Mais, les fonctions suivantes (pour toutes les variables) ne fonctionnent pas ne fonctionne pas:
avec .:
df_1 %>% select(-y) %>% rowwise() %>% mutate(var = sum(.))
avec select_if :
library(tidyverse) df_1 %>% select(-y) %>% rowwise() %>% mutate(var = sum(c(x.1, x.3)))
Les deux méthodes renvoient:
df_1 <- data.frame( x = replicate(4, runif(30, 20, 100)), y = sample(1:3, 30, replace = TRUE) )
Où 7091 est une somme incorrecte.
Comment l'ajustement fonctionne-t-il?
4 Réponses :
Je pense que c'est délicat parce que les variantes de portée de mutate ( mutate_at , mutate_all , mutate_if ) visent généralement à exécuter une fonction sur une colonne spécifique, au lieu de créer une opération qui utilise toutes les colonnes.
La solution la plus simple que je puisse trouver consiste essentiellement à créer un vecteur ( cols ) qui est ensuite utilisé pour exécuter l'opération récapitulative :
library(dplyr)
library(purrr)
df_1 <- data.frame(
x = replicate(4, runif(30, 20, 100)),
y = sample(1:3, 30, replace = TRUE)
)
# create vector of columns to operate on
cols <- names(df_1)
cols <- cols[map_lgl(df_1, is.numeric)]
cols <- cols[! cols %in% c("y")]
cols
#> [1] "x.1" "x.2" "x.3" "x.4"
df_1 %>%
select(-y) %>%
rowwise() %>%
mutate(
var = sum(!!!map(cols, as.name), na.rm = TRUE)
)
#> Source: local data frame [30 x 5]
#> Groups: <by row>
#>
#> # A tibble: 30 x 5
#> x.1 x.2 x.3 x.4 var
#> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 46.1 28.9 28.9 50.7 155.
#> 2 26.8 68.0 67.1 26.5 188.
#> 3 35.2 63.8 62.5 28.5 190.
#> 4 31.3 44.9 67.3 68.2 212.
#> 5 52.6 23.9 83.2 43.4 203.
#> 6 55.7 92.8 86.3 57.2 292.
#> 7 56.9 50.0 77.6 25.6 210.
#> 8 95.0 82.6 86.1 22.7 286.
#> 9 62.7 26.5 61.0 88.9 239.
#> 10 65.2 23.1 25.5 51.0 165.
#> # ⦠with 20 more rows
Créé le 30/04/2019 par package reprex (v0.2.1)
REMARQUE: si vous n'êtes pas familier avec purrr , vous pouvez également utiliser quelque chose comme lapply code>, etc.
Vous pouvez en savoir plus sur ces types d'opérations dplyr plus délicates ( !! , !!! code>, etc.) ici:
https: //dplyr.tidyverse .org / articles / programmation.html
Quelques approches que j'ai adoptées dans le passé:
rowSums ) réduire (qui ne s'applique pas à toutes les fonctions) pmap my_var <- function(...){
vec <- c(...)
var(vec)
}
df_1 %>%
mutate(var = select(., -y) %>% pmap(my_var)) %>%
head()
#> x.1 x.2 x.3 x.4 y var
#> 1 41.24069 58.56641 93.03007 39.17035 3 620.9523
#> 2 49.76991 67.96527 43.48827 24.71475 2 318.3722
#> 3 65.82827 59.48330 56.72526 71.38306 2 43.17011
#> 4 92.65662 34.89741 46.59157 90.10154 1 878.5009
#> 5 36.13455 86.18987 72.06964 82.31317 3 520.7224
#> 6 91.87117 73.47734 40.64134 83.78471 2 506.1679
df_1 %>% mutate(var = select(., -y) %>% as.matrix %>% t %>% as.data.frame %>% map_dbl(var)) %>% head() #> x.1 x.2 x.3 x.4 y var #> 1 41.24069 58.56641 93.03007 39.17035 3 620.95228 #> 2 49.76991 67.96527 43.48827 24.71475 2 318.37221 #> 3 65.82827 59.48330 56.72526 71.38306 2 43.17011 #> 4 92.65662 34.89741 46.59157 90.10154 1 878.50087 #> 5 36.13455 86.18987 72.06964 82.31317 3 520.72241 #> 6 91.87117 73.47734 40.64134 83.78471 2 506.16785
df_1 %>% mutate(var = reduce(select(., -y),`+`)) %>% head() #> x.1 x.2 x.3 x.4 y var #> 1 41.24069 58.56641 93.03007 39.17035 3 232.0075 #> 2 49.76991 67.96527 43.48827 24.71475 2 185.9382 #> 3 65.82827 59.48330 56.72526 71.38306 2 253.4199 #> 4 92.65662 34.89741 46.59157 90.10154 1 264.2471 #> 5 36.13455 86.18987 72.06964 82.31317 3 276.7072 #> 6 91.87117 73.47734 40.64134 83.78471 2 289.7746
pmapset.seed(1) df_1 <- data.frame( x = replicate(4, runif(30, 20, 100)), y = sample(1:3, 30, replace = TRUE) ) library(tidyverse) # rowSums df_1 %>% mutate(var = rowSums(select(., -y))) %>% head() #> x.1 x.2 x.3 x.4 y var #> 1 41.24069 58.56641 93.03007 39.17035 3 232.0075 #> 2 49.76991 67.96527 43.48827 24.71475 2 185.9382 #> 3 65.82827 59.48330 56.72526 71.38306 2 253.4199 #> 4 92.65662 34.89741 46.59157 90.10154 1 264.2471 #> 5 36.13455 86.18987 72.06964 82.31317 3 276.7072 #> 6 91.87117 73.47734 40.64134 83.78471 2 289.7746
Créé le 2019-04-30 par le package reprex (v0.2.1)
Au lieu de + , je peux mettre mean , var (répondre avec réduire )? Comment puis-je faire ceci?
Je l'ai mis à jour avec var , en utilisant une stratégie différente. Ce n'est pas particulièrement élégant (je suppose qu'il y a des fonctions personnalisées par ligne pour beaucoup de choses), mais cette approche fonctionnerait généralement tant que toutes les colonnes -y sont du même type.
Cela peut être fait en utilisant purrr :: pmap a >, qui passe une liste d'arguments à une fonction qui accepte les "points". Étant donné que la plupart des fonctions telles que mean , sd , etc. fonctionnent avec des vecteurs, vous devez associer l'appel avec un domain lifter :
df_1 %>% select(-y) %>%
mutate( v1 = pmap(., lift_vd(mean)),
v2 = pmap(., lift_vd(sd)),
v3 = pmap(., sum) )
# x.1 x.2 x.3 x.4 v1 v2 v3
# 1 70.12072 62.99024 54.00672 86.81358 68.48282 13.88555 273.9313
# 2 49.40462 47.00752 21.99248 78.87789 49.32063 23.27958 197.2825
La fonction sum accepte directement les points, donc vous ne t besoin de lever son domaine:
df_1 %>% select(-y) %>% mutate( var = pmap(., sum) ) # x.1 x.2 x.3 x.4 var # 1 70.12072 62.99024 54.00672 86.81358 273.9313 # 2 49.40462 47.00752 21.99248 78.87789 197.2825
Tout est conforme au traitement de données standard dplyr , donc les trois peuvent être combinés comme arguments séparés pour muter :
df_1 %>% select(-y) %>% mutate( var = pmap(., lift_vd(mean)) ) # x.1 x.2 x.3 x.4 var # 1 70.12072 62.99024 54.00672 86.81358 68.48282 # 2 49.40462 47.00752 21.99248 78.87789 49.32063 df_1 %>% select(-y) %>% mutate( var = pmap(., lift_vd(sd)) ) # x.1 x.2 x.3 x.4 var # 1 70.12072 62.99024 54.00672 86.81358 13.88555 # 2 49.40462 47.00752 21.99248 78.87789 23.27958
Merci. Mais, et pour plus que la fonction? Exemple, pour mean , sd et var (3 nouvelles colonnes)? Voir: mutate (var = pmap (., Lift_vd (mean, sd, var))) ne fonctionne pas.
@GiovaniNeves: Combinez simplement ceux à l'intérieur de mutate comme vous le feriez normalement. Voir la modification ci-dessus.
Excellente solution! Merci, @Artem Sokolov!
C'est un problème délicat car dplyr opère par colonne pour de nombreuses opérations. J'ai utilisé à l'origine apply à partir de la base R pour appliquer sur les lignes, mais apply est problématique lors de la gestion des caractères et des types numériques .
Au lieu de cela, nous pouvons utiliser (le vieillissement) plyr strong> et adply a > pour faire cela simplement, puisque plyr nous permet de traiter un bloc de données à une ligne comme un vecteur:
df_1 %>% select(-y) %>% adply(1, function(df) c(v1 = sd(df[1, ])))
Notez certaines fonctions comme var won ' t travailler sur une trame de données à une ligne, nous devons donc convertir en vecteur en utilisant as.numeric .
Vous pouvez utiliser
rowSums:df_1%>% mutate (var = rowSums (select (., Starts_with ('x.'))))@IceCreamToucan, j'ai besoin d'utiliser
rowwise.cette répond à votre question?
Ça ne marche pas. J'ai besoin d'une somme pour chaque cas (ligne) pour toutes les variables.
Peut être fait en utilisant le package
purrr:df_1%>% select (-y)%>% mutate (var = pmap (., Lift (sum)))Et
signifieousd?@GiovaniNeves: C'est la même chose pour
meanetsd. Utilisez simplement un autre lifter de domaine:df_1%>% select (-y)%>% mutate (var = pmap (., Lift_vd (mean)))