【问题标题】:Replacing values bigger than threshold with 0 in specified range of columns in R dataframe在R数据框中的指定列范围内将大于阈值的值替换为0
【发布时间】:2021-12-29 05:57:48
【问题描述】:

我有一个数据集 df1,其中的列从 S_2018_pS_2021_p 我想将 >= 10 的值替换为 0。我希望有一个像 df2 这样的数据集。

library(data.table)
df1 = data.table(
  ID = c("a1", "a2", "a3", "a4", "a5", "a6", "a7"),
  "string1" = c("x2", "g3", "n2", "m3", "2w", "ps2", "kg2"),
  "S_2018_p" = c(3,5,11,3,9,22,6),
  "S_2019_p" = c(3,5,6,21,1,4,0),
  "S_2020_p" = c(0,4,13,9,16,7,9),
  "S_2021_p" = c(4,0,3,8,5,4,6),
  "string2" = c("si", "q2", "oq", "mx", "ix", "p2", "2q"))

  ID string1 S_2018_p S_2019_p S_2020_p S_2021_p string2
1: a1      x2        3        3        0        4      si
2: a2      g3        5        5        4        0      q2
3: a3      n2       11        6       13        3      oq
4: a4      m3        3       21        9        8      mx
5: a5      2w        9        1       16        5      ix
6: a6     ps2       22        4        7        4      p2
7: a7     kg2        6        0        9        6      2q
df2 = data.table(
  ID = c("a1", "a2", "a3", "a4", "a5", "a6", "a7"),
  "string1" = c("x2", "g3", "n2", "m3", "2w", "ps2", "kg2"),
  "S_2018_p" = c(3,5,0,3,9,0,6),
  "S_2019_p" = c(3,5,6,0,1,4,0),
  "S_2020_p" = c(0,4,0,9,0,7,9),
  "S_2021_p" = c(4,0,3,8,5,4,6),
  "string2" = c("si", "q2", "oq", "mx", "ix", "p2", "2q"))

   ID string1 S_2018_p S_2019_p S_2020_p S_2021_p string2
1: a1      x2        3        3        0        4      si
2: a2      g3        5        5        4        0      q2
3: a3      n2        0        6        0        3      oq
4: a4      m3        3        0        9        8      mx
5: a5      2w        9        1        0        5      ix
6: a6     ps2        0        4        7        4      p2
7: a7     kg2        6        0        9        6      2q

我尝试使用 mutete_if 执行此操作,但没有得到所需的输出。

df1 %>% 
  mutate_if(is.numeric, ~1 * (. >= 10))

【问题讨论】:

    标签: r dataframe tidyverse


    【解决方案1】:

    Dplyr(使用最新版本)有一个很好的“across()”函数可以与 mutate 一起使用。请务必更新您的 dplyr 软件包,因为它是最新的

    library(dplyr)
    
    df1 %>% mutate(across(where(is.numeric), function(x) ifelse(x >= 10, 0, x)))
    
       ID string1 S_2018_p S_2019_p S_2020_p S_2021_p string2
    1: a1      x2        3        3        0        4      si
    2: a2      g3        5        5        4        0      q2
    3: a3      n2        0        6        0        3      oq
    4: a4      m3        3        0        9        8      mx
    5: a5      2w        9        1        0        5      ix
    6: a6     ps2        0        4        7        4      p2
    7: a7     kg2        6        0        9        6      2q
    
    

    【讨论】:

    • 非常感谢这个简短直观的解决方案!
    【解决方案2】:

    另一种解决方案,基于dplyr

    library(tidyverse)
    library(data.table)
    
    df1 = data.table(
      ID = c("a1", "a2", "a3", "a4", "a5", "a6", "a7"),
      "string1" = c("x2", "g3", "n2", "m3", "2w", "ps2", "kg2"),
      "S_2018_p" = c(3,5,11,3,9,22,6),
      "S_2019_p" = c(3,5,6,21,1,4,0),
      "S_2020_p" = c(0,4,13,9,16,7,9),
      "S_2021_p" = c(4,0,3,8,5,4,6),
      "string2" = c("si", "q2", "oq", "mx", "ix", "p2", "2q"))
    
    df1 %>% 
      mutate(
        across(
          where(is.numeric),
          ~ if_else(get(cur_column()) > 10, 0, get(cur_column()))))
    
    #>    ID string1 S_2018_p S_2019_p S_2020_p S_2021_p string2
    #> 1: a1      x2        3        3        0        4      si
    #> 2: a2      g3        5        5        4        0      q2
    #> 3: a3      n2        0        6        0        3      oq
    #> 4: a4      m3        3        0        9        8      mx
    #> 5: a5      2w        9        1        0        5      ix
    #> 6: a6     ps2        0        4        7        4      p2
    #> 7: a7     kg2        6        0        9        6      2q
    

    还有另一个解决方案,基于purrr::map_if

    library(tidyverse)
    library(data.table)
    
    df1 = data.table(
      ID = c("a1", "a2", "a3", "a4", "a5", "a6", "a7"),
      "string1" = c("x2", "g3", "n2", "m3", "2w", "ps2", "kg2"),
      "S_2018_p" = c(3,5,11,3,9,22,6),
      "S_2019_p" = c(3,5,6,21,1,4,0),
      "S_2020_p" = c(0,4,13,9,16,7,9),
      "S_2021_p" = c(4,0,3,8,5,4,6),
      "string2" = c("si", "q2", "oq", "mx", "ix", "p2", "2q"))
    
    df1 %>% map_if(is.numeric, ~ ifelse(.x > 10 , 0, .x)) %>% as.data.table
    
    #>    ID string1 S_2018_p S_2019_p S_2020_p S_2021_p string2
    #> 1: a1      x2        3        3        0        4      si
    #> 2: a2      g3        5        5        4        0      q2
    #> 3: a3      n2        0        6        0        3      oq
    #> 4: a4      m3        3        0        9        8      mx
    #> 5: a5      2w        9        1        0        5      ix
    #> 6: a6     ps2        0        4        7        4      p2
    #> 7: a7     kg2        6        0        9        6      2q
    

    【讨论】:

    • 非常感谢,两个版本都可以使用
    【解决方案3】:

    您可以在感兴趣的特定列上使用applyifelse 函数。例如:

    apply(df1[,c(3,4,5,6)], MARGIN = c(1,2), FUN = function(x) ifelse(x >= 10, 0, x))
    

    apply 函数将作用于数据框的选定行 (df1[,c(3,4,5,6)]) 并将应用函数 FUN = ifelse(x >= 10, 0, x)(如果 x 大于或等于 10,则将其替换为 0,否则,将其替换用它自己(不要替换它))在数据框的每个单元格上(MARGIN = c(1,2))。

    你当然可以用更正的部分替换数据框部分:

    df1[,c(3,4,5,6)] <- apply(df1[,c(3,4,5,6)], MARGIN = c(1,2), FUN = function(x) ifelse(x >= 10, 0, x))
    

    【讨论】:

    • 感谢您的快速回复!
    猜你喜欢
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 2020-03-16
    • 1970-01-01
    相关资源
    最近更新 更多