Le mutate peut-il être utilisé lorsque la mutation est conditionnelle (en fonction des valeurs de certaines valeurs de colonne)?
Cet exemple aide à montrer ce que je veux dire.
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame")
a b c d e f
1 1 1 6 6 1 2
2 3 3 3 2 2 3
3 4 4 6 4 4 4
4 6 2 5 5 5 2
5 3 6 3 3 6 2
6 2 7 6 7 7 7
7 5 2 5 2 6 5
8 1 6 3 6 3 2
J'espérais trouver une solution à mon problème en utilisant le package dplyr (et oui je sais que ce n'est pas du code qui devrait fonctionner, mais je suppose que cela rend le but clair) pour créer une nouvelle colonne g:
library(dplyr)
df <- mutate(df,
if (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)){g = 2},
if (a == 0 | a == 1 | a == 4 | a == 3 | c == 4) {g = 3})
Le résultat du code que je recherche devrait avoir ce résultat dans cet exemple particulier:
a b c d e f g
1 1 1 6 6 1 2 3
2 3 3 3 2 2 3 3
3 4 4 6 4 4 4 3
4 6 2 5 5 5 2 NA
5 3 6 3 3 6 2 NA
6 2 7 6 7 7 7 2
7 5 2 5 2 6 5 2
8 1 6 3 6 3 2 3
Quelqu'un a-t-il une idée sur la façon de faire cela dans dplyr? Cette trame de données n'est qu'un exemple, les trames de données dont je traite sont beaucoup plus grandes. En raison de sa vitesse, j'ai essayé d'utiliser dplyr, mais peut-être existe-t-il d'autres meilleurs moyens de gérer ce problème?
dplyr::case_when()
c'est beaucoup plus clair qu'unifelse
,Réponses:
Utilisation
ifelse
Ajouté - if_else: Notez que dans dplyr 0.5 il y a une
if_else
fonction définie donc une alternative serait de remplacerifelse
parif_else
; cependant, notez que puisqueif_else
est plus strict queifelse
(les deux branches de la condition doivent avoir le même type) doncNA
dans ce cas devrait être remplacé parNA_real_
.Ajouté - case_when Depuis que cette question a été publiée, dplyr a ajouté
case_when
une autre alternative serait:Ajouté - arithmétique / na_if Si les valeurs sont numériques et les conditions (à l'exception de la valeur par défaut de NA à la fin) sont mutuellement exclusives, comme c'est le cas dans la question, alors nous pouvons utiliser une expression arithmétique telle que chaque terme est multiplié par le résultat souhaité en utilisant
na_if
à la fin pour remplacer 0 par NA.la source
NA
, je veux que les lignes qui ne remplissent pas les conditions restent les mêmes?mutate(g = ifelse(condition1, 2, ifelse(condition2, 3, g))
Puisque vous demandez d'autres meilleures façons de gérer le problème, voici une autre façon d'utiliser
data.table
:Notez que l'ordre des instructions conditionnelles est inversé pour obtenir
g
correctement. Il n'y a pas de copie deg
made, même pendant la deuxième mission - elle est remplacée sur place .Sur des données plus volumineuses, cela aurait de meilleures performances que l'utilisation imbriquée
if-else
, car il peut évaluer à la fois les cas «oui» et «non» , et l'imbrication peut devenir plus difficile à lire / maintenir à mon humble avis.Voici un benchmark sur des données relativement plus volumineuses:
Je ne sais pas si c'est une alternative que vous aviez demandée, mais j'espère que cela vous aidera.
la source
DT_fun
modifie son entrée en place, le benchmark peut ne pas être tout à fait juste - en plus de ne pas recevoir la même entrée de la 2ème itération vers l'avant (ce qui pourrait affecter le timing carDT$g
est déjà alloué?), Le résultat se propage également versans1
et pourrait donc ( si l'optimiseur de R le juge nécessaire? Pas sûr à ce sujet ...) éviter une autre copieDPLYR_fun
et que vousBASE_fun
devez faire?data.table
solution est excellente, et je l'utilisedata.table
partout où j'ai vraiment besoin de vitesse pour les opérations sur les tables et je ne veux pas aller jusqu'au C ++. Il faut cependant faire très attention aux modifications en place!dplyr a maintenant une fonction
case_when
qui offre un if vectorisé. La syntaxe est un peu étrange comparée àmosaic:::derivedFactor
car vous ne pouvez pas accéder aux variables de la manière standard de dplyr, et devez déclarer le mode de NA, mais c'est considérablement plus rapide quemosaic:::derivedFactor
.EDIT: Si vous utilisez une
dplyr::case_when()
version antérieure à 0.7.0 du paquet, vous devez alors faire précéder les noms de variables avec '.$
' (par exemple écrire à l'.$a == 1
intérieurcase_when
).Benchmark : Pour le benchmark (réutilisation des fonctions du poste d'Arun) et réduction de la taille de l'échantillon:
Cela donne:
la source
case_when
pourrait aussi s'écrire:df %>% mutate(g = with(., case_when(a %in% c(2,5,7) | (a==1 & b==4) ~ 2L, a %in% c(0,1,3,4) | c==4 ~ 3L, TRUE ~ NA_integer_)))
.$
dans la nouvelle version de dplyrLa
derivedFactor
fonction demosaic
package semble être conçue pour gérer cela. En utilisant cet exemple, cela ressemblerait à:(Si vous souhaitez que le résultat soit numérique au lieu d'un facteur, vous pouvez encapsuler
derivedFactor
unas.numeric
appel.)derivedFactor
peut également être utilisé pour un nombre arbitraire de conditions.la source
.asFactor = F
option ou en utilisant la fonction (similaire)derivedVariable
dans le même package.recode
dplyr 0.5 fera cela. Cependant, je n'ai pas encore enquêté dessus. Voir blog.rstudio.org/2016/06/27/dplyr-0-5-0case_when
est maintenant une implémentation assez propre du cas de style SQL lorsque:Utilisation de dplyr 0.7.4
Le manuel: http://dplyr.tidyverse.org/reference/case_when.html
la source