当 tidyselect 的 any_of() 没有匹配到任何列时,可以使用 dplyr 的 rename_with()。

3

我在使用 rename_with() 和 tidyselector any_of() 时遇到了困难,如果后者中没有匹配项。

看这个例子:

library(tidyvese)

iris |> 
  rename_with(.cols = any_of(contains("Length")),
              .fn = ~ifelse(str_detect(.x, "Petal"),
                      paste0(.x,  "_[petal_var]"),
                      paste0(.x, "_[sepal_var]")))

它的作用基本上是检查是否有包含字符串"Length"的变量,然后根据变量是否包含字符串"Petal"应用函数:

  • 是:则用"_[petal_var]"后缀重命名

  • 否:则用"_[sepal_var]"后缀重命名

但是只要至少有一个变量匹配any_of()调用,此方法就有效。

让我们考虑一个没有匹配的示例:

iris |> 
  rename_with(.cols = any_of(contains("UNMATCHED_STRING")),
              .fn = ~ifelse(str_detect(.x, "Petal"),
                      paste0(.x,  "_[petal_var]"),
                      paste0(.x, "_[sepal_var]")))

这会返回:

Error in `rename_with()`:
! `.fn` must return a character vector, not an empty logical vector.
Run `rlang::last_error()` to see where the error occurred.

我理解这个问题:没有东西可以传递给.fn参数,因为没有变量与tidyselect .col步骤匹配。

不幸的是,我没有看到使用rename_with()的解决方法(在这里非常需要)。在我更复杂的情况下,我需要将相当复杂的重命名函数传递给可能包含或不包含any_of(contains(...))值的不同数据集。

任何帮助都将不胜感激。

2个回答

3

你可以使用一个 if/else 语句来处理:

if(any(grepl("Length", colnames(iris)))){
  iris <- 
    iris |>
    rename_with(.cols = everything(),
                .fn = ~ ifelse(str_detect(.x, "Petal"),
                               paste0(.x,  "_[petal_var]"),
                               paste0(.x, "_[sepal_var]")))
  iris
} else iris

这个答案在这个非常特定的情况下有效,所以谢谢!但是它不太优雅,我正在寻找一个更简单的选项,在rename_with()的调用内忽略.fn,如果没有匹配。如果没有更合适的方案,我会验证这个! - Michaël Weber
我同意,虽然我想不到其他的方法。对我来说,“any_of”是一个相当模糊的函数。 - Maël

3

关于此问题的讨论,请参见:https://github.com/tidyverse/dplyr/issues/6688

最简单的解决方法是设置参数paste0(recycle0 = TRUE)。所以在你的情况下,这应该可以解决:

iris |> 
  rename_with(.cols = any_of(contains("UNMATCHED_STRING")),
              .fn = ~ifelse(str_detect(.x, "Petal"),
                      paste0(.x,  "_[petal_var]", recycle0 = TRUE),
                      paste0(.x, "_[sepal_var]", recycle0 = TRUE)))

dplyr 包的维护者们在 rename_with 手册页面中加入了一个示例来解决这个问题。


2
这应该是我个人的认为可以接受的答案。这是一个通用解决方案,只需要对paste0函数进行微小修改即可。(仍然无法确定recycle0 = TRUE实际上是做什么的,但可以确认这个方法有效。) - Earlien

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