将跨数据帧的共享数据列中的多个值重新编码/替换为单个值

时间:2019-01-03 06:20:58

标签: r dplyr lapply purrr

我希望我不会错过它,但是我一直无法找到解决该问题的可行方法。 我有一组带有共享列的数据框。这些列包含多个变化的转录错误,对于多个值,其中一些是共享的,而其他则不共享。 我想用所有数据帧中的正确值(good_values)替换/重新编码转录错误(bad_values)。

我尝试过将map*()函数系列嵌套在数据帧,bad_values和good_values列表中,以实现此目的。这是一个示例:

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

我不一定希望能超越一个单一的好坏值对。但是,我认为在此嵌套另一个对map*()的调用可能会起作用:

dfs = map(df_list, function(x) {
x %>% mutate(grp = map2(bad_values, good_values, function(x,y) {
recode(grp, bad_values = good_values)})
})

我尝试了许多其他方法,但都没有奏效。

最终,我想从一组有错误的数据帧开始,如下所示:

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

对于“固定”数据帧的列表,例如:

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

任何帮助将不胜感激

3 个答案:

答案 0 :(得分:3)

这是将tidyverserecode_factor一起使用的选项。如果有多个要更改的元素,请创建一个{/ {1}}键/值元素,然后使用list进行匹配并将值更改为新的recode_factor

levels

-输出

library(tidyverse)
keyval <- setNames(rep(good_values, lengths(bad_values)), unlist(bad_values))
out <- map(df_list, ~ .x %>% 
                  mutate(grp = recode_factor(grp, !!! keyval)))

注意:这不会更改初始数据集列的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 #....

class

一旦有了密钥对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 ,它也可以在list函数中使用

base R

答案 1 :(得分:2)

映射case_when语句的任何原因都不起作用?

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

我认为它可以为您的reprex工作,但可能不是更大的问题。

答案 2 :(得分:1)

如果您有很多good_valuesbad_values并且无法单独检查每个基础R选项。

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

在这里,对于每个列表元素,我们提取其grp列,并将bad_values替换为相应的good_values(如果找到)并返回校正后的数据帧。