Построчные операции, выбор помощников и функция изменения в 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() function is not given any .data аргумент. So I change the code in...

... my second try by adding "." внутри 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

The new problem after the second try is that the mean column does not contain the mean of a_2 а также b_2 as expected, but contains NaNтолько с After studying the code a bit, I understood the second problem. The added "." в select() function refers to the original my_df data frame, which does not have the a_2 а также b_2 колонны. So it makes sense that NaNs are produced because I am asking R to compute the means of nonexistent values.

Затем я попытался использовать dplyr такие функции, как current_vars() to see if it would make a difference:

 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.

However, this is obviously NOT the way to use this function. The solution is to simply add a second 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

Question 1: Is there any way to perform this task in the same mutate() вызов? Используя второй mutate() function is not really an issue anyway; however, I am curious to know if there exists a way to refer to currently existing variables. mutate() function allows for the usage of variables as soon as they are created inside the same mutate() вызов; however, this becomes problematic when functions are nested as shown in my example above.

Часть 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(), но я показываю это, чтобы спросить, есть ли способ перечислить переменные, которые я хочу, без необходимости указывать их по отдельности.

Спасибо за ваше время.

2 ответа

Немного поздно, но вот решение проблемы 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 дважды. Так что в пайп-версии вам понадобится также ссылка . явно во второй раз (как обычно, первая ссылка неявная, как первый аргумент для изменения):

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-способ сделать именно то, что вы искали, используя c_across. Это полезно, поскольку расширяет решение для других функций, которые могут иметь реализацию Row, например RowMeans().

Попробуй это:

      my_df %>%
  mutate(
    a_2 = a^2,
    b_2 = b^2,
    ) %>% 
  rowwise() %>% 
  mutate( mean = mean(c_across(ends_with("2"))) )
Другие вопросы по тегам