【问题标题】:recode/replace multiple values in a shared data column to a single value across data frames将共享数据列中的多个值重新编码/替换为跨数据帧的单个值
【发布时间】:2019-05-29 17:53:03
【问题描述】:

我希望我没有错过它,但我还没有找到解决这个问题的有效解决方案。 我有一组带有共享列的数据框。这些列包含多个不同的转录错误,其中一些是共享的,而另一些则不是,用于多个值。 我想用所有数据帧中的正确值 (good_values) 替换/重新编码转录错误 (bad_values)。

我尝试在数据框、bad_values 和 good_values 列表中嵌套 map*() 系列函数来执行此操作,等等。这是一个例子:

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

任何帮助将不胜感激

【问题讨论】:

    标签: r dplyr lapply purrr


    【解决方案1】:

    这是一个使用tidyverserecode_factor 的选项。当有多个元素要更改时,创建一个key/val元素的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
    

    一旦我们有了一个 keyval 对 list,这也可以在 base R 函数中使用

    out1 <- lapply(df_list, transform, grp = unlist(keyval[grp]))
    

    【讨论】:

      【解决方案2】:

      如果您有很多 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,并返回正确的数据帧。

      【讨论】:

        【解决方案3】:

        映射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 有效,但可能不是更大的问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-08-06
          • 1970-01-01
          • 2016-07-24
          • 1970-01-01
          • 1970-01-01
          • 2021-08-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多