gpt4 book ai didi

R:Tidyverse 选择语义 tidyselect::eval_select 将数字附加到重复项

转载 作者:行者123 更新时间:2023-12-04 11:35:23 25 4
gpt4 key购买 nike

我试图了解 tidyverse 设计以及如何使用它进行编程有一段时间了。我试图编写一个使用 tidyselect 语义的函数,我发现 tidyselect::eval_select将数字附加到 lhs 表达式。看到这个语义用于列重命名,这并不奇怪。不幸的是,我用于构建数据结构的函数不需要这种行为,它需要表达式的 lhs 中提供的常规名称(根据需要重复多次)。我还没有设法找出这种行为的来源;好像是 make.unique但我找不到它在哪里实现。如果你知道,我很想学习,如果没有,解决我的问题不应该依赖于它。
我想要的只是 lhs 名称没有附加数字,如示例所示:

library(tidyverse)

# Data
data <- mtcars[, 8:11]

# Example
data %>%
tidyselect::eval_select(rlang::expr(c(foo = 1, bar = c(2:4), foobar = c(1, "am", "gear", "carb"))), .)
#> foo bar1 bar2 bar3 foobar1 foobar2 foobar3 foobar4
#> 1 2 3 4 1 2 3 4

# Function
test <- function(.data, ...) {
loc <- tidyselect::eval_select(rlang::expr(c(...)), .data)
names <- names(.data)
list(names(loc), names[loc])
}

data %>%
test(foo = 1, bar = c(2:4), foobar = c(1, "am", "gear", "carb"))
#> [[1]]
#> [1] "foo" "bar1" "bar2" "bar3" "foobar1" "foobar2" "foobar3"
#> [8] "foobar4"
#>
#> [[2]]
#> [1] "vs" "am" "gear" "carb" "vs" "am" "gear" "carb"
创建于 2021-05-22 由 reprex package (v2.0.0)
期望的输出:
#> [[1]]
#> [1] "foo" "bar" "bar" "bar" "foobar" "foobar" "foobar"
#> [8] "foobar"
#>
#> [[2]]
#> [1] "vs" "am" "gear" "carb" "vs" "am" "gear" "carb"
任何帮助是极大的赞赏。

最佳答案

该问题是由名为 ensure_named 的函数引起的。深深嵌套在里面 eval_select l 实现。它是 vars_select_eval 的一部分功能。ensure_named(pos, vars, uniquely_named, allow_rename)好消息是我们只需要覆盖 uniquely_named参数,这个参数是从第一个名为 eval_select_impl 的实现函数开始的。由 eval_select 调用本身。所以我们需要做的就是重写tidyselect::eval_select .
为了获得想要的输出,我们需要做两件事:

  • 添加 uniquely_named = NULL作为参数并用 FALSE 指定它调用函数时
  • 指定现有参数 name_spec = "{outer}" .除非 uniquely_named 只做这一步是不够的设置为 FALSE .

  • 在实际代码之前,请注意: tidyselect::eval_select故意不允许重复的列名。
    首先,要创建一个 tibble 是不可能的。列名重复:
    tibble(a = 1:3, b = 4:6, a = 7:9)
    #> Error: Column name `a` must not be duplicated.
    #> Use .name_repair to specify repair.
    一种解决方法是使用带有 tibble::new_tibble 的列表。 :
    tibble::new_tibble(list(a = 1:3, b = 4:6, a = 7:9), nrow = 3)
    #> # A tibble: 3 x 3
    #> a b a
    #> <int> <int> <int>
    #> 1 1 4 7
    #> 2 2 5 8
    #> 3 3 6 9
    对于 data.framecheck.names 时,只能创建非唯一名称。参数设置为 FALSE :
    data.frame(a = 1:3, b = 4:6, a = 7:9, check.names = FALSE)
    #> a b a
    #> 1 1 4 7
    #> 2 2 5 8
    #> 3 3 6 9
    但是当我们使用这个 data.frame使用常规的 {dplyr} 动词,会抛出错误,告诉我们不能转换具有重复名称的数据框:

    data.frame(a = 1:3, b = 4:6, a = 7:9, check.names = FALSE) %>% 
    mutate(c = 1:3)
    #> Error: Can't transform a data frame with duplicate names.
    所以由此我们可以假设不推荐使用 data.frame在 {tidyverse} 中具有重复名称的 s。它可能与整洁数据的概念相矛盾。
    话虽如此,下面是上述解决此问题的方法:

    library(tidyverse)

    # Data
    data <- mtcars[, 8:11]

    # custom eval_select function
    my_eval_select <- function(expr, data,
    env = rlang::caller_env(),
    ..., include = NULL,
    exclude = NULL, strict = TRUE,
    name_spec = NULL,
    uniquely_named = NULL, # this is the new argument
    allow_rename = TRUE) {
    ellipsis::check_dots_empty()
    tidyselect:::eval_select_impl(data, names(data), rlang::as_quosure(expr, env),
    include = include, exclude = exclude, strict = strict,
    name_spec = name_spec, allow_rename = allow_rename,
    uniquely_named = uniquely_named) # which we also add here
    }

    # example 1
    data %>%
    my_eval_select(rlang::expr(c(foo = 1, bar = c(2:4), foobar = c(1, "am", "gear", "carb"))),
    data = .,
    name_spec = "{outer}", # we need to specify this
    uniquely_named = FALSE) # and this
    #> foo bar bar bar foobar foobar foobar foobar
    #> 1 2 3 4 1 2 3 4

    # example: custom function
    test <- function(.data, ...) {
    loc <- my_eval_select(rlang::expr(c(...)),
    data = .data,
    name_spec = "{outer}",
    uniquely_named = FALSE)
    names <- names(.data)
    list(names(loc), names[loc])
    }

    # test
    data %>%
    test(foo = 1, bar = c(2:4), foobar = c(1, "am", "gear", "carb"))
    #> [[1]]
    #> [1] "foo" "bar" "bar" "bar" "foobar" "foobar" "foobar" "foobar"
    #>
    #> [[2]]
    #> [1] "vs" "am" "gear" "carb" "vs" "am" "gear" "carb"
    创建于 2021-05-22 由 reprex package (v0.3.0)

    关于R:Tidyverse 选择语义 tidyselect::eval_select 将数字附加到重复项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67649636/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com