4
votes

recoder / remplacer plusieurs valeurs dans une colonne de données partagée en une seule valeur dans les blocs de données

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


0 commentaires

3 Réponses :


2
votes

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 >


0 commentaires

1
votes

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é.


0 commentaires

3
votes

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)))


0 commentaires