使用dplyr中的case_when和across函数

15

我正在尝试使用dplyr的新“across”函数将mutate_at()翻译为mutate(),但有点困惑。

简而言之,我需要比较一系列列中的值与“基准”列的值。当列中的值高于基准时,我需要使用基准值。当列中的值低于或等于基准时,我需要保留该值。以下是一个示例数据集(我的实际数据集要大得多):

test <- structure(list(baseline = c(5, 7, 8, 4, 9, 1, 0, 46, 47), bob = c(7, 
11, 34, 9, 6, 8, 3, 49, 12), sally = c(3, 5, 2, 2, 6, 1, 3, 4, 
56), rita = c(6, 4, 6, 7, 6, 0, 3, 11, 3)), class = c("spec_tbl_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -9L), spec = structure(list(
    cols = list(baseline = structure(list(), class = c("collector_double", 
    "collector")), bob = structure(list(), class = c("collector_double", 
    "collector")), sally = structure(list(), class = c("collector_double", 
    "collector")), rita = structure(list(), class = c("collector_double", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), skip = 1), class = "col_spec"))

我的当前代码使用mutate_at(),运行良好:

trial1 <- test %>% 
  mutate_at(
    vars('bob','sally', 'rita'),
    funs(case_when(
      . > baseline ~ baseline, 
      . <= baseline ~ .)))

但是当我尝试使用dplyr 1.0的across()函数进行更新时,我一直收到一个错误。这是我的尝试:

但是当我尝试使用dplyr 1.0的across()函数进行更新时,我一直收到一个错误。这是我的尝试:

trial2 <- test %>% 
  mutate(across(c(bob, sally, rita), 
                case_when(. > baseline ~ baseline, 
                          . <= baseline ~ .)))

这里是错误信息:

错误: mutate() 的输入参数 ..1 存在问题。 x . > baseline ~ baseline, . <= baseline ~ . 的长度必须为 36 或 1,而不是 9 和 4。 ℹ 输入参数 ..1across(...)

有任何想法我可能做错了什么吗?case_when() 能和 across 一起使用吗?

1个回答

34

我们可以使用 ~ 来指定匿名函数/lambda函数的调用。

library(dplyr)
test %>% 
   mutate(across(c(bob, sally, rita), 
             ~ case_when(. > baseline ~ baseline, 
                       . <= baseline ~ .)))

-输出

# A tibble: 9 x 4
#  baseline   bob sally  rita
#     <dbl> <dbl> <dbl> <dbl>
#1        5     5     3     5
#2        7     7     5     4
#3        8     8     2     6
#4        4     4     2     4
#5        9     6     6     6
#6        1     1     1     0
#7        0     0     0     0
#8       46    46     4    11
#9       47    12    47     3

根据?across的说明,fns的参数可以是以下值:

对所选列要应用的函数。可能的取值有:

NULL,返回未转换的列。

一个函数,例如mean。

一个purrr风格的lambda,例如~ mean(.x, na.rm = TRUE)

一组函数/lambda,例如list(mean = mean, n_miss = ~ sum(is.na(.x))


另外,除了使用case_when之外,我们还可以利用pmin

test %>% 
    mutate(across(c(bob, sally, rita), ~ pmin(baseline, .)))

-输出

# A tibble: 9 x 4
#  baseline   bob sally  rita
#     <dbl> <dbl> <dbl> <dbl>
#1        5     5     3     5
#2        7     7     5     4
#3        8     8     2     6
#4        4     4     2     4
#5        9     6     6     6
#6        1     1     1     0
#7        0     0     0     0
#8       46    46     4    11
#9       47    12    47     3

Akrun,你的第三个代码块中是不是应该用 funs 而不是 fns?如果我使用 funs 运行它,它不会出错但也不会有任何改变。而如果我使用 fns,就会出现 across 错误,因为 fns 必须是 NULL/函数/公式/列表等。 - dez93_2000
1
@dez93_2000 我其实不记得这里的上下文是什么了,因为那是在2020年。函数中的参数可能会被更改,或者可能是我的错误。无论哪种情况,我都无法使用当前版本的dplyr进行适当的测试。所以,我将其删除了。 - akrun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接