Je sais qu'il y a plusieurs questions similaires ici, mais aucune ne semble répondre au problème précis que j'ai.
set.seed(4)
df = data.frame(
Key = c("A", "B", "A", "D", "A"),
Val1 = rnorm(5),
Val2 = runif(5),
Val3 = 1:5
)
Je veux mettre à zéro les valeurs des colonnes de valeurs pour les lignes où Clé == "A" Les noms des colonnes sont référencés via un grep
:
cols = grep("Val", names(df), value = TRUE)
Normalement, pour réaliser ce que je veux dans ce cas, j'utiliserais data.table
ceci:
library(data.table)
df = as.data.table(df)
df[Key == "A", (cols) := 0]
Et la sortie souhaitée est comme ceci:
Key Val1 Val2 Val3
1 A 0.000000 0.00000000 0
2 B -1.383814 0.55925762 2
3 A 0.000000 0.00000000 0
4 D 1.437151 0.05632773 4
5 A 0.000000 0.00000000 0
Cependant, cette fois, je dois l'utiliser dplyr
car je travaille sur un projet d'équipe où tout le monde l'utilise. Les données que je viens de fournir sont illustratives et mes données réelles sont> 5 m de lignes avec 16 colonnes de valeurs à mettre à jour. La seule solution que j'ai pu trouver est d'utiliser mutate_at
comme ceci:
df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))
Cependant, cela semble être extrêmement lent sur mes données réelles. J'espérais trouver une solution plus élégante et surtout plus rapide.
J'ai essayé de nombreuses combinaisons en utilisant map
, en ne citant pas en utilisant !!
, en utilisant get
et :=
(qui peuvent être masquées de manière agaçante par la :=
table de données), etc., mais je pense que ma compréhension de la façon dont ces travaux ne sont tout simplement pas assez profonds pour construire une solution valide.
la source
Réponses:
Avec cette commande dplyr,
Vous évaluez actuellement l'instruction df $ Key == "A", n fois, où n = le nombre de colonnes que vous avez.
Une solution consiste à prédéfinir les lignes que vous souhaitez modifier:
Une manière plus propre et meilleure, correctement indiquée par @IceCreamToucan (voir les commentaires ci-dessous), consiste à utiliser la fonction replace, tout en lui passant les paramètres supplémentaires:
Nous pouvons tester toutes ces approches, et je pense que dplyr et data.table sont comparables.
la source
df %>% mutate_at(vars(contains('Val')), replace, df$Key == 'A', 0)
replace
méthode soit un peu plus lente que votreidx
méthode d' origine .dplyr::if_else()
c'est plus rapide que la baseifelse()
.