Построчные операции, выбор помощников и функция изменения в 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 NaN
s 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"))) )