首页 > 解决方案 > 为什么我的 dplyr 百分位数计算不适用于 tidy 评估?

问题描述

我有一个学生测试数据,我希望将这些数据转换为百分位数dplyr。为了有一个最小的例子,想象一下三个学生的以下设置。

require(tidyverse)

tbl <- tibble(Name = c("Alice", "Bob", "Cat"), Test = c(16, 13, 15))

以下代码有效并产生所需的输出。

tbl %>% mutate(TestPercentile = cume_dist(Test) * 100)

# A tibble: 3 x 3
  Name   Test TestPercentile
  <chr> <dbl>          <dbl>
1 Alice    16          100  
2 Bob      13           33.3
3 Cat      15           66.7

但是,我实际上想以编程方式进行,因为有很多这样的列。

colname <- "Test"
percname <- str_c(colname, "Percentile")
tbl %>% mutate({{percname}} := cume_dist({{colname}}) * 100)

# A tibble: 3 x 3
  Name   Test TestPercentile
  <chr> <dbl>          <dbl>
1 Alice    16            100
2 Bob      13            100
3 Cat      15            100

cume_dist当我尝试使用这样的 tidy 评估时,为什么要让所有学生的百分位数为 100?(理想情况下,如果允许我提出第二个问题,我该如何解决?)

标签: rdplyrtidyeval

解决方案


如果通过编程你的意思是你想编写自己的函数,你可以这样做:

calculate_percentile <- function(data, colname) {

   data %>% 
    mutate("{{colname}}Percentile" := cume_dist({{colname}} * 100))

}

tbl %>% 
  calculate_percentile(Test)

 # A tibble: 3 x 3
  Name   Test TestPercentile
  <chr> <dbl>          <dbl>
1 Alice    16          1    
2 Bob      13          0.333
3 Cat      15          0.667

编辑多列 新数据

tbl <- tibble(Name = c("Alice", "Bob", "Cat"), Test = c(16, 13, 15), Test_math = c(16, 30, 55), Test_music = c(3, 78, 34))
calculate_percentile <- function(data, colnames) {

  data %>% 

    mutate(across({{colnames}}, ~cume_dist(.) * 100, .names = "{col}Percentile"))

}

test_columns <- c("Test_math", "Test_music")
tbl %>% 
  calculate_percentile(test_columns) 

# A tibble: 3 x 6
  Name   Test Test_math Test_music Test_mathPercentile Test_musicPercentile
  <chr> <dbl>     <dbl>      <dbl>               <dbl>                <dbl>
1 Alice    16        16          3                33.3                 33.3
2 Bob      13        30         78                66.7                100  
3 Cat      15        55         34               100                   66.7

为什么您的解决方案不起作用?因为您的解决方案cume_dist从字面上适用于字符串“test”:

tbl %>% mutate({{percname}} := print({{colname}}))

[1] "Test"
# A tibble: 3 x 5
  Name   Test Test_math Test_music TestPercentile
  <chr> <dbl>     <dbl>      <dbl> <chr>         
1 Alice    16        16          3 Test          
2 Bob      13        30         78 Test          
3 Cat      15        55         34 Test 

为什么这会给出TestPercentile100 的值?因为cume_dist“测试”是1:

cume_dist("test")
#[1] 1

所以我们需要 R 告诉我们不要评估字符串“test”本身,而是寻找具有这个名称的变量,我们可以这样做:

tbl %>% mutate({{percname}} := cume_dist(!!parse_quo(colname, env = global_env())) * 100)

# A tibble: 3 x 5
  Name   Test Test_math Test_music TestPercentile
  <chr> <dbl>     <dbl>      <dbl>          <dbl>
1 Alice    16        16          3          100  
2 Bob      13        30         78           33.3
3 Cat      15        55         34           66.7

#Check that this uses the values of "Test" and not "Test" per se:
tbl %>% mutate({{percname}} := print(!!parse_quo(colname, env = global_env())))

[1] 16 13 15
# A tibble: 3 x 5
  Name   Test Test_math Test_music TestPercentile
  <chr> <dbl>     <dbl>      <dbl>          <dbl>
1 Alice    16        16          3             16
2 Bob      13        30         78             13
3 Cat      15        55         34             15

推荐阅读