按行操作,select 助手和 dplyr 中的 mutate 函数

row-wise operations, select helpers and the mutate function in dplyr

我将使用以下数据集来说明我的问题:

my_df <- data.frame(
    a = 1:10,
    b = 10:1
)
colnames(my_df) <- c("a", "b")

第 1 部分

我使用 mutate() 函数在我的数据集中创建两个新变量,我想在同一个 mutate() 调用中计算两个新列的行均值。但是,我真的很想能够使用 select() 助手,例如 starts_with()ends_with()contains()

我的第一次尝试:

 my_df %>%
    mutate(
        a_2 = a^2,
        b_2 = b^2,
        mean = rowMeans(select(ends_with("2")))
    )
Error in mutate_impl(.data, dots) : 
  Evaluation error: No tidyselect variables were registered.

我明白为什么会出现错误 - select() 函数没有给出任何 .data 参数。所以我更改了代码...

...我第二次尝试在 select() 函数中添加“.”:

my_df %>%
    mutate(
        a_2 = a^2,
        b_2 = b^2,
        mean = rowMeans(select(., ends_with("2")))
    )
    a  b a_2 b_2 mean
1   1 10   1 100  NaN
2   2  9   4  81  NaN
3   3  8   9  64  NaN
4   4  7  16  49  NaN
5   5  6  25  36  NaN
6   6  5  36  25  NaN
7   7  4  49  16  NaN
8   8  3  64   9  NaN
9   9  2  81   4  NaN
10 10  1 100   1  NaN

第二次尝试后的新问题是mean列没有像预期的那样包含a_2b_2的均值,而是只包含NaNs .稍微研究了一下代码,我明白了第二个问题。 select()函数中添加的“.”指的是原来的my_df数据框,没有a_2b_2两列。所以产生 NaN 是有道理的,因为我要求 R 计算不存在值的均值。

然后我尝试使用 dplyr 函数,例如 current_vars() 看看它是否会有所作为:

 my_df %>%
    mutate(
        a_2 = a^2,
        b_2 = b^2,
        mean = rowMeans(select(current_vars(), ends_with("2")))
    )
Error in mutate_impl(.data, dots) : 
  Evaluation error: Variable context not set.

但是,这显然不是使用此功能的方式。解决方案是简单地添加第二个 mutate() 函数:

 my_df %>%
    mutate(
        a_2 = a^2,
        b_2 = b^2
    ) %>%
    mutate(mean = rowMeans(select(., ends_with("2"))))
    a  b a_2 b_2 mean
1   1 10   1 100 50.5
2   2  9   4  81 42.5
3   3  8   9  64 36.5
4   4  7  16  49 32.5
5   5  6  25  36 30.5
6   6  5  36  25 30.5
7   7  4  49  16 32.5
8   8  3  64   9 36.5
9   9  2  81   4 42.5
10 10  1 100   1 50.5

问题 1:有什么方法可以在同一个 mutate() 调用中执行此任务?无论如何,使用第二个 mutate() 函数并不是真正的问题;但是,我很想知道是否存在一种方法来引用当前存在的变量。 mutate() 函数允许在同一 mutate() 调用中创建变量后立即使用它们;但是,当函数如我上面的示例所示嵌套时,这就会成为问题。

第 2 部分

我还意识到在我的解决方案中使用 rowMeans() 是可行的;但是,它并不是真正的 dplyr 做事方式,尤其是因为我需要在其中使用 select()。因此,我决定改用 rowwise()mean() 函数。但再一次,我想为此使用 select() 助手之一,而不必在 c() 函数中列出所有变量。我试过了:

 my_df %>%
    mutate(
        a_2 = a^2,
        b_2 = b^2
    ) %>%
    rowwise() %>%
    mutate(
        mean = mean(ends_with("2"))
    )
Error in mutate_impl(.data, dots) : 
  Evaluation error: No tidyselect variables were registered.

我怀疑代码中的错误是由于 ends_with() 不在 select() 内,但我展示这个是想问是否有办法列出我的变量想要而不必单独指定它们。

感谢您的宝贵时间。

有点晚了,这里给出问题1的解决方法,供参考。

如果你不得不在没有管道的情况下这样做,你会写:

tmp1 = mutate(my_df, a_2 = a^2, b_2 = b^2)
tmp2 = select(tmp1, ends_with("2"))
tmp3 = rowMeans(tmp2)
tmp4 = mutate(tmp1, m=tmp3)

或者,中间步骤较少:

tmp1 = mutate(my_df, a_2 = a^2, b_2 = b^2)
tmp4 = mutate(tmp1, m=rowMeans(select(tmp1, ends_with("2"))) )

请注意,计算 tmp4 需要使用 tmp1 两次。因此,在管道版本中,您还需要第二次显式引用 .(像往常一样,第一次引用是隐式的,作为 mutate 的第一个参数):

my_df %>%
  mutate(a_2 = a^2, b_2 = b^2) %>%
  mutate(mean = rowMeans(select(., ends_with("2"))) )

对于问题 #2:避免调用 rowMeans 比较棘手,而且可能不可取 (?)

幸运的是,由于 dplyr > 1.0.0 有一个 dplyr-way 可以通过使用 c_across 来完成您正在寻找的事情。这很有用,因为它将解决方案扩展到可能具有 RowMeans() 等 Row 实现的其他函数。

试试这个:

my_df %>%
  mutate(
    a_2 = a^2,
    b_2 = b^2,
    ) %>% 
  rowwise() %>% 
  mutate( mean = mean(c_across(ends_with("2"))) )