【问题标题】:R dplyr - making 'count' function work in summarize_at chainR dplyr - 使“计数”功能在summarize_at链中工作
【发布时间】:2020-11-06 16:01:03
【问题描述】:

这是来自 R 中 dplyr 库的数据框 starwars。我正在尝试使用 dplyr 编写聚合表,主要使用 group_by_atsummarize_at 链。我已经定义了向量dimensionsVecmeasuresVec 和函数。目标是使用分配给数据帧pivotDatadplyr 链中的所有三个向量。

不幸的是,count = length 参数在运行 pivotData 后尝试吐出数据帧时不起作用。这可能是由于na.rm = TRUE 声明。所以基本上,除了函数中的count = length 参数外,一切都正常。您可以通过注释掉 `functions 向量的 count = length 部分来找到它。

有人可以帮助我吗?非常感谢您的帮助!

下面的代码sn-p

library(dplyr)

data <- starwars

dimensionsVec <- c("skin_color", "eye_color")
measuresVec <- c("height", "mass")

functions <- c(count = "length", 
               mean = "mean", 
               sum = "sum", 
               median = "median", 
               max = "max", 
               min = "min")

funsList <- lapply(functions, match.fun)
names(funsList) <- functions

pivotData <- data %>%
  group_by_at(vars(dimensionsVec)) %>%
  summarize_at(vars(measuresVec), funsList, na.rm = TRUE) %>%
  collect()

【问题讨论】:

    标签: r function dplyr pivot


    【解决方案1】:

    你只需要小心你传递的函数。您不能将na.rm = TRUE 参数添加到summarize_at,除非它可以传递给列表中的所有函数。但是,如果将na.rm = TRUE 传递给length,则会抛出错误。

    解决此问题的一种方法是围绕length 创建一个包装器,该包装器采用na.rm 参数:

    funsList <- list(count = function(x, na.rm) length(x),
                     mean = mean,
                     sum = sum, 
                     median = median, 
                     max = max, 
                     min = min)
    

    (请注意,您可以直接使用不带引号的函数名,而不是将它们全部作为字符串并使用match.fun

    这种方法有效,但它揭示了代码中的另一个问题。您正在总结的某些组没有非 NA 条目,因此您在某些组上有效地执行min(NA, na.rm = TRUE)。这会导致警告并在您可能不想要的结果中返回 Inf 而不是 NA。你同样会从meanmedian 得到一个不需要的-InfmaxNaN

    解决方案是具体说明您希望每个函数在这种情况下执行的操作。例如,您可以创建一个小函数,将摘要函数作为参数并返回它们的 NA 安全版本:

    handle_NA <- function(func) 
    {
      function(x) if(all(is.na(x))) NA else func(x, na.rm = TRUE) 
    }
    

    这允许您像这样创建一个安全的funsList

    funsList <- list(count = length,
                     mean = handle_NA(mean),
                     sum = handle_NA(sum),
                     median = handle_NA(median), 
                     max = handle_NA(max), 
                     min = handle_NA(min))
    
    data %>%
      group_by(across(all_of(dimensionsVec))) %>%
      summarize(across(all_of(measuresVec), funsList), .groups = "drop")
    #> # A tibble: 53 x 14
    #>    skin_color eye_color height_count height_mean height_sum height_median
    #>    <chr>      <chr>            <int>       <dbl>      <int>         <dbl>
    #>  1 blue       blue                 1        196         196          196 
    #>  2 blue       hazel                1        178         178          178 
    #>  3 blue, grey yellow               2        116.        231          116.
    #>  4 brown      blue                 1        234         234          234 
    #>  5 brown      brown                2        130.        259          130.
    #>  6 brown      yellow               1        198         198          198 
    #>  7 brown mot~ orange               1        180         180          180 
    #>  8 brown, wh~ green, y~            1        216         216          216 
    #>  9 dark       blue                 1        184         184          184 
    #> 10 dark       brown                4        183.        733          184 
    #> # ... with 43 more rows, and 8 more variables: height_max <int>,
    #> #   height_min <int>, mass_count <int>, mass_mean <dbl>, mass_sum <dbl>,
    #> #   mass_median <dbl>, mass_max <dbl>, mass_min <dbl>
    

    请注意,作用域动词 summarize_atgroup_by_at 已被 across 取代,因此我已切换到更现代的语法。

    【讨论】:

      猜你喜欢
      • 2018-06-13
      • 1970-01-01
      • 2018-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-20
      • 1970-01-01
      • 2021-03-05
      相关资源
      最近更新 更多