J'espère ne pas l'avoir manqué, mais je n'ai pas été en mesure de trouver une solution efficace à ce problème. J'ai un ensemble de cadres de données avec une colonne partagée. Ces colonnes contiennent des erreurs de transcription multiples et variables, dont certaines sont partagées, d'autres non, pour plusieurs valeurs. Je voudrais remplacer / recoder les erreurs de transcription (bad_values) par les valeurs correctes (good_values) dans toutes les trames de données.
J'ai essayé d'imbriquer la famille de fonctions map * ()
dans des listes de données frames, bad_values et good_values pour ce faire, entre autres. Voici un exemple:
[[1]] grp measure 1 a -0.7671052 2 a 0.1781247 3 a -0.7565773 4 b -0.3606900 5 b 1.9264804 6 b 0.9506608 [[2]] grp measure 1 a 1.45036125 2 a -2.16715639 3 a 0.80105611 4 b 0.24216723 5 a 1.33089426 6 a -0.08388404 [[3]] grp measure 1 b 1 2 b 2 3 b 3 4 b 4 5 b 5 6 a 6
Ce que je ne m'attendais pas nécessairement à travailler au-delà d'une seule paire de bonnes / mauvaises valeurs. Cependant, je pensais que l'imbrication d'un autre appel à map * ()
dans ceci pourrait fonctionner:
[[1]] grp measure 1 a1 0.5582253 2 a. 0.3400904 3 a. -0.2200824 4 b -0.7287385 5 b -0.2128275 6 b 1.9030766 [[2]] grp measure 1 as 1.6148772 2 as 0.1090853 3 as -1.3714180 4 b2 -0.1606979 5 a 1.1726395 6 a -0.3201150 [[3]] grp measure 1 b- 1 2 b- 2 3 b- 3 4 bq 4 5 bq 5 6 a 6
J'ai essayé un certain nombre d'autres approches, aucune qui ont fonctionné.
En fin de compte, j'aimerais passer d'un ensemble de blocs de données contenant des erreurs, comme ici:
dfs = map(df_list, function(x) { x %>% mutate(grp = map2(bad_values, good_values, function(x,y) { recode(grp, bad_values = good_values)}) })
À une liste de ' fixes 'data frames, en tant que tels:
df1 = data.frame(grp = c("a1","a.","a.",rep("b",7)), measure = rnorm(10)) df2 = data.frame(grp = c(rep("as", 3), "b2",rep("a",22)), measure = rnorm(26)) df3 = data.frame(grp = c(rep("b-",3),rep("bq",2),"a", rep("a.", 3)), measure = 1:9) df_list = list(df1, df2, df3) bad_values = list(c("a1","a.","as"), c("b2","b-","bq")) good_values = list("a", "b") dfs = map(df_list, function(x) { x %>% mutate(grp = plyr::mapvalues(grp, bad_values, rep(good_values,length(bad_values)))) })
Toute aide serait très appréciée
3 Réponses :
Une raison pour laquelle le mappage d'une instruction case_when
ne fonctionnerait pas?
library(tidyverse) df_list %>% map(~ mutate_if(.x, is.factor, as.character)) %>% # convert factor to character map(~ mutate(.x, grp = case_when(grp %in% bad_values[[1]] ~ good_values[[1]], grp %in% bad_values[[2]] ~ good_values[[2]], TRUE ~ grp)))
Je pourrais le voir fonctionner pour votre reprex mais peut-être pas le plus gros problème. p >
Une option de base R si vous avez beaucoup de good_values
et bad_values
et qu'il n'est pas possible de vérifier chacun d'eux individuellement.
lapply(df_list, function(x) { vec = x[['grp']] mapply(function(p, q) vec[vec %in% p] <<- q ,bad_values, good_values) transform(x, grp = vec) }) #[[1]] # grp measure #1 a -0.648146527 #2 a -0.004722549 #3 a -0.943451194 #4 b -0.709509396 #5 b -0.719434286 #.... #[[2]] # grp measure #1 a 1.03131291 #2 a -0.85558910 #3 a -0.05933911 #4 b 0.67812934 #5 a 3.23854093 #6 a 1.31688645 #7 a 1.87464048 #8 a 0.90100179 #.... #[[3]] # grp measure #1 b 1 #2 b 2 #3 b 3 #4 b 4 #5 b 5 #....
Ici, pour chaque élément de liste, nous extrayons la colonne grp
et remplaçons bad_values
par les good_values
correspondants si ils sont trouvés et renvoient le dataframe corrigé.
Voici une option utilisant tidyverse
avec recode_factor
. Lorsqu'il y a plusieurs éléments à modifier, créez une liste
d'éléments clé / valeur et utilisez recode_factor
pour faire correspondre et changer les valeurs en de nouveaux niveaux
out1 <- lapply(df_list, transform, grp = unlist(keyval[grp]))
-output
str(out) #List of 3 # $ :'data.frame': 10 obs. of 2 variables: # ..$ grp : Factor w/ 2 levels "a","b": 1 1 1 2 2 2 2 2 2 2 # ..$ measure: num [1:10] -1.633 0.0386 -0.4654 -0.7236 -1.1155 ... # $ :'data.frame': 26 obs. of 2 variables: # ..$ grp : Factor w/ 2 levels "a","b": 1 1 1 2 1 1 1 1 1 1 ... # ..$ measure: num [1:26] 1.265 -0.482 0.23 -1.013 -1.416 ... # $ :'data.frame': 9 obs. of 2 variables: # ..$ grp : Factor w/ 2 levels "a","b": 2 2 2 2 2 1 1 1 1 # ..$ measure: int [1:9] 1 2 3 4 5 6 7 8 9
REMARQUE: Cela ne change pas la classe
de la colonne de l'ensemble de données initiale
out #[[1]] # grp measure #1 a -1.63295876 #2 a 0.03859976 #3 a -0.46541610 #4 b -0.72356671 #5 b -1.11552841 #6 b 0.99352861 #.... #[[2]] # grp measure #1 a 1.26536789 #2 a -0.48189740 #3 a 0.23041056 #4 b -1.01324689 #5 a -1.41586086 #6 a 0.59026463 #.... #[[3]] # grp measure #1 b 1 #2 b 2 #3 b 3 #4 b 4 #5 b 5 #6 a 6 #....
Une fois que nous avons une liste
de paires de clés, elle peut également être utilisée dans les fonctions base R
p>
library(tidyverse) keyval <- setNames(rep(good_values, lengths(bad_values)), unlist(bad_values)) out <- map(df_list, ~ .x %>% mutate(grp = recode_factor(grp, !!! keyval)))