Je veux remplacer NA par la valeur du groupe (pas la moyenne ou la médiane, car certaines colonnes sont des caractères ou des facteurs) et je veux faire cela pour une liste de colonnes utilisant le même groupe pour tous.
Exemple de données:
mydf[,-c(1] <- lapply(mydf, function(x) replace(x, is.na(x), x[!is.na(x)])) > mydf ID V1 V2 V3 V4 1 1 1 HEJ 700 3 2 1 1 HEJ 700 1 3 1 1 BOS 700 3 4 2 2 BOS 3000 1 5 2 2 BOS 700 1 6 2 2 BOS 3000 1 7 3 3 IB 1000 2 8 3 3 IB 1000 1
Donc, je sais que si je ne voulais faire cela que pour une colonne, je:
names <- colnames(mydf[,-c(1)])
for(j in seq_along(nm1)){
set(mydf,
i = which(is.na(mydf[[names[j]]])),
j = names[j],
value = mydf[[names[j]]][is.na(mydf[[names[j]]])])
}
Et puis j'obtiendrais:
> mydf ID V1 V2 V3 V4 1: 1 HEJ 700 3 <NA> 2: 1 HEJ 700 3 <NA> 3: 1 HEJ 700 3 <NA> 4: 2 BOS 3000 1 LA 5: 2 BOS 3000 1 LA 6: 2 BOS 3000 1 LA 7: 3 IB 1000 2 FE 8: 3 IB 1000 2 FE
Mais j'ai beaucoup de colonnes, donc je dois les mettre dans une boucle.
Résultat souhaité:
> mydf ID V1 V2 V3 V4 1: 1 HEJ 700 NA <NA> 2: 1 HEJ 700 NA <NA> 3: 1 HEJ NA 3 <NA> 4: 2 BOS 3000 1 <NA> 5: 2 BOS NA 1 <NA> 6: 2 BOS NA 1 LA 7: 3 IB NA 2 <NA> 8: 3 IB 1000 NA FE
Et voici ce que j'ai essayé sans chance:
setDT(mydf)[, V1:=
V1[!is.na(V1)][1L],
by = ID]
Et j'ai aussi essayé ceci:
ID <- c(1,1,1,2,2,2,3,3) V1 <- c(NA,"HEJ",NA,"BOS","BOS",NA,"IB","IB") V2 <- c(700,700,NA,3000,NA,NA,NA,1000) V3 <- c(NA,NA,3,1,1,1,2,NA) V4 <- c(NA,NA,NA,NA,NA,"LA",NA,"FE") mydf <- data.frame(ID,V1,V2,V3,V4) > mydf ID V1 V2 V3 V4 1 1 <NA> 700 NA <NA> 2 1 HEJ 700 NA <NA> 3 1 <NA> NA 3 <NA> 4 2 BOS 3000 1 <NA> 5 2 BOS NA 1 <NA> 6 2 <NA> NA 1 LA 7 3 IB NA 2 <NA> 8 3 IB 1000 NA FE
Je suis désolé si je pose une question qui existe déjà mais je n'ai pas pu la trouver. J'espère que quelqu'un pourra m'aider à nettoyer mes données désordonnées :)
3 Réponses :
Une possibilité de dplyr et tidyr pourrait être:
mydf %>%
group_by(ID) %>%
fill(-ID, .direction = "downup")
ID V1 V2 V3 V4
<dbl> <fct> <dbl> <dbl> <fct>
1 1 HEJ 700 3 <NA>
2 1 HEJ 700 3 <NA>
3 1 HEJ 700 3 <NA>
4 2 BOS 3000 1 LA
5 2 BOS 3000 1 LA
6 2 BOS 3000 1 LA
7 3 IB 1000 2 FE
8 3 IB 1000 2 FE
Edit: demandé si cela fonctionne si la valeur inférieure est NA, mais je peux voir que mes exemples de données ont déjà un cas de colonne comme celui-ci (V3)
Pouvez-vous s'il vous plaît élaborer cette question? Je ne suis pas sûr de comprendre :)
Cela ne fonctionne pas sur mes exemples de données ... J'obtiens l'erreur "Erreur dans match.arg (.direction): 'arg' devrait être l'un des" down "," up ""
essayé avec le haut et le bas, et aucun des deux ne fournit la sortie souhaitée
Cet argument est relativement nouveau, essayez de mettre à jour vers la dernière version de tidyr .
Nous pouvons utiliser .SDcols pour appliquer la fonction à plusieurs colonnes.
library(data.table)
cols <- names(mydf[-1])
setDT(mydf)
mydf[, (cols):= lapply(.SD, function(x)
replace(x, is.na(x), x[!is.na(x)][1])),.SDcols = cols, by = ID]
mydf
# ID V1 V2 V3 V4
#1: 1 HEJ 700 3 <NA>
#2: 1 HEJ 700 3 <NA>
#3: 1 HEJ 700 3 <NA>
#4: 2 BOS 3000 1 LA
#5: 2 BOS 3000 1 LA
#6: 2 BOS 3000 1 LA
#7: 3 IB 1000 2 FE
#8: 3 IB 1000 2 FE
Merci, ça marche, mais ça écrase pour ces colonnes sans NA et je ne veux pas ça, donc je pense que pour mon cas, le remplissage fonctionne mieux. Merci quand même. C'était quelque chose comme ça que je cherchais.
@ LouiseSørensen Mise à jour de la réponse pour ne remplacer que les valeurs NA .
Nous pouvons utiliser na.locf de zoo
library(data.table) setDT(df1)[, na.locf(.SD), by = ID, .SDcols = V2:V4]