【问题标题】:Applying mutate() and case_when() for each element in the dataframe using dplyr/tidyr?使用 dplyr/tidyr 对数据框中的每个元素应用 mutate() 和 case_when()?
【发布时间】:2021-03-12 14:48:23
【问题描述】:

我原来有一个数据集,大小为:1652行,50列,但在这个例子中本质是一样的。数据集是 df,我希望以 newdf 结尾。有人知道如何使用 dplyr 解决这个问题吗?

df <- cbind(c("HouseCar", "Car", "carmouse", "mouse", NA),
                  c("car", NA, "Mousehouse", "housevan", NA),
                   c(NA, "mousevan", "Carhouse", NA, "mouse"))

     df
     [,1]       [,2]         [,3]      
[1,] "HouseCar" "car"        NA        
[2,] "Car"      NA           "mousecar"
[3,] "carmouse" "Mousehouse" "Carhouse"
[4,] "mouse"    "house"      NA        
[5,] NA         NA           "mouse"  

期望的输出(有一个重新编码层次结构房屋>车辆(面包车,汽车)>鼠标):

> newdf
     [,1]      [,2]      [,3]     
[1,] "House"   "Vehicle" NA       
[2,] "Vehicle" NA        "Vehicle"
[3,] "Vehicle" "House"   "House"  
[4,] "Mouse"   "House"   NA       
[5,] NA        NA        "Mouse" 

我打算这样做,但我想知道为什么这段代码不起作用?

newdf <- df %>% 
  replace_na(., NA_character_) %>% 
  tolower(.) %>% 
  mutate_all(case_when(
    str_detect(., "house") ~ "House",
    str_detect(., "car|van") ~ "Vehicle",
    str_detect(., "mouse") ~ "Mouse",
    TRUE ~ NA_character_
    )
  )
  

我不断收到此错误消息:

UseMethod("tbl_vars") 中的错误: 没有适用于“c('matrix', 'array', 'character')”类对象的“tbl_vars”方法

【问题讨论】:

    标签: r tidyr dplyr


    【解决方案1】:

    为此,df 需要是 tibble 或数据框对象。 cbind 的输出是一个矩阵,这也是您收到错误的部分原因。

    df <- data.frame(df)
    names(df) <- paste0("col", 1:3)
    
    df %>% 
      mutate(across(everything(), ~ case_when(
        str_detect(.x, "house") ~ "House",
        str_detect(.x, "car|van") ~ "Vehicle",
        str_detect(.x, "mouse") ~ "Mouse",
        T ~ NA_character_
      )))
    

    从 dplyr 1.0.0 版开始,几乎所有带有 _at、_all、_if 等的动词都被 across 动词取代。您可以使用packageVersion("dplyr")查看您的版本。

    dplyr

    df %>% 
      mutate_all(~ case_when(
        str_detect(.x, "house") ~ "House",
        str_detect(.x, "car|van") ~ "Vehicle",
        str_detect(.x, "mouse") ~ "Mouse",
        T ~ NA_character_
      ))
    

    输出

         col1    col2    col3
    1    <NA> Vehicle    <NA>
    2    <NA>    <NA> Vehicle
    3 Vehicle   House   House
    4   Mouse   House    <NA>
    5    <NA>    <NA>   Mouse
    

    更新

    要忽略大小写,您可以做一些事情:

    1. 正如您在 cmets 中提到的,您可以在应用函数之前将大小写更改为所有内容:
    df %>% 
      mutate(across(everything(), tolower)) # pipe to rest of code
    
    1. 您可以使用stringr::regex 忽略str_detect 上的大小写:
    df %>% 
      mutate(across(everything(), ~ case_when(
        str_detect(.x, regex("house", ignore_case = T)) ~ "House",
        str_detect(.x, regex("car|van", ignore_case = T)) ~ "Vehicle",
        str_detect(.x, regex("mouse", ignore_case = T)) ~ "Mouse",
        T ~ NA_character_
      )))
    
    1. 内置函数grepl 做同样的事情:
    df %>% 
      mutate(across(everything(), ~ case_when(
        grepl("house", .x, ignore.case = T) ~ "House",
        grepl("car|van", .x, ignore.case = T) ~ "Vehicle",
        grepl("mouse", .x, ignore.case = T) ~ "Mouse",
        T ~ NA_character_
      )))
    
    

    【讨论】:

    • 感谢您的帮助!你知道我们如何使字符串匹配对大写字母不敏感吗?
    • 我一直在尝试使用 mutate(across(tolower(.))),但最终得到: get(.x, .env, mode = "function") 中的错误:object 'list (x1 = c("gange_t-bane", "", "bil (kjørte selv)", "gange_buss", "sykkel", "bil (kjørte selv)"))' 模式'function'没有找到。外文文本相当于示例中的“house, mouse, van/car”。
    • across 的第一个参数是您希望使用 tidyselect 语法在哪些列上应用您的函数。这就是为什么在我的代码中我使用了everything(),它将case_when 应用于所有列。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2022-09-26
    相关资源
    最近更新 更多