【问题标题】:Using mutate_at with mutate_if将 mutate_at 与 mutate_if 一起使用
【发布时间】:2020-06-23 14:39:05
【问题描述】:

我正在我的包中创建一个通用函数。目标是找到百分比列,然后在它们是 character 列时对它们使用 parse_number。我还没有找到使用mutate_at 和ifelse 的解决方案。我在下面粘贴了一个代表。

 library(tidyverse)


df <- tibble::tribble(
  ~name, ~pass_percent, ~attendance_percent, ~grade,
  "Jon",         "90%",                0.85,    "B",
  "Jim",        "100%",                   1,    "A"
  )

percent_names <- df %>% select(ends_with("percent"))%>% names()


# Error due to attendance_percent already being in numeric value

if (percent_names %>% length() > 0) {
    df <-
      df %>%
      dplyr::mutate_at(percent_names, readr::parse_number)
  }
#> Error in parse_vector(x, col_number(), na = na, locale = locale, trim_ws = trim_ws): is.character(x) is not TRUE

【问题讨论】:

    标签: r dplyr readr


    【解决方案1】:

    您的attendance_percent 变量是数字,而不是字符,parse_number 只需要字符变量,请参阅here。所以一个解决方案是:

    edited_parse_number <- function(x, ...) {
      if (mode(x) == 'numeric') {
        x
      } else {
        parse_number(x, ...)
      }
    }
    
    
    df %>%
      dplyr::mutate_at(vars(percent_names), edited_parse_number)
    
    #  name  pass_percent attendance_percent grade
    #  <chr>        <dbl>              <dbl> <chr>
    #1 Jon             90               0.85 B    
    #2 Jim            100               1    A   
    

    或

    如果您不想使用该额外功能,请在开头提取字符变量:

    percent_names <- df %>% 
      select(ends_with("percent")) %>% 
      select_if(is.character) %>% 
      names()
    percent_names
    # [1] "pass_percent"
    
    
    df %>%
      dplyr::mutate_at(vars(percent_names), parse_number)
    #   name  pass_percent attendance_percent grade
    #   <chr>        <dbl>              <dbl> <chr>
    # 1 Jon             90               0.85 B    
    # 2 Jim            100               1    A    
    

    【讨论】:

      【解决方案2】:

      或者,无需创建函数,您只需将ifelse 语句添加到mutate_at 中,例如:

      if (percent_names %>% length() > 0) {
        df <-
          df %>% rowwise() %>%
          dplyr::mutate_at(vars(percent_names), ~ifelse(is.character(.), 
                                                        parse_number(.),
                                                        .))
      }
      
      Source: local data frame [2 x 4]
      Groups: <by row>
      
      # A tibble: 2 x 4
        name  pass_percent attendance_percent grade
        <chr>        <dbl>              <dbl> <chr>
      1 Jon             90               0.85 B    
      2 Jim            100               1    A    
      

      【讨论】:

      • 这比我的回答更简洁,但您的最终 . 正在更改您输出中的数字?
      • 好的,我先添加rowwise 来纠正它。但不确定其背后的逻辑。
      • 谢谢,但是 rowwise 是做什么的?
      • 不客气;)。 rowwise 将逐行评估数据帧 (dplyr.tidyverse.org/reference/rowwise.html)。不确定,为什么这里需要它,但似乎 ifelse 语句将评估 percent_names 列的第一行,然后将 TRUE 或 FALSE 条件应用于第一行。
      猜你喜欢
      • 1970-01-01
      • 2019-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-20
      • 2020-01-27
      • 2018-02-03
      相关资源
      最近更新 更多