Я вижу два способа сделать это: простой способ, который становится намного сложнее, если у вас есть или вы получите больше уровней с метками, и один, который немного больше кода, но может быть более устойчивым к большим данным.
1: Легко, но плохо масштабируется
x %>%
group_by(label_a) %>%
mutate(x_mean = mean(if_else(label_b == "x", value, value[NA]), na.rm = TRUE)) %>%
ungroup()
# # A tibble: 8 x 4
# label_a label_b value x_mean
# <chr> <chr> <dbl> <dbl>
# 1 a x 1 2
# 2 a x 3 2
# 3 a y 6 2
# 4 a y 8 2
# 5 b x 10 20
# 6 b x 30 20
# 7 b y 60 20
# 8 b y 80 20
Суть этого в том, что мы берем среднее значение только из "x"
значений, опуская остальные.Использование if_else
дает векторизованное выражение if / then-like, а использование value[NA]
гарантирует, что мы получим «правильный вид NA
» (существует более чем несколько различных NA
sв R).
2: более надежный
x %>%
filter(label_b == "x") %>%
group_by(label_a) %>%
summarize(x_mean = mean(value)) %>%
left_join(x, ., by = "label_a") %>%
ungroup()
# # A tibble: 8 x 4
# label_a label_b value x_mean
# <chr> <chr> <dbl> <dbl>
# 1 a x 1 2
# 2 a x 3 2
# 3 a y 6 2
# 4 a y 8 2
# 5 b x 10 20
# 6 b x 30 20
# 7 b y 60 20
# 8 b y 80 20
В этом случае сначала создается сводная таблица:
x %>%
filter(label_b == "x") %>%
group_by(label_a) %>%
summarize(x_mean = mean(value))
# # A tibble: 2 x 2
# label_a x_mean
# <chr> <dbl>
# 1 a 2
# 2 b 20
, а затем слияние это обратно в оригинальную рамку.В базе R мы будем использовать merge
, в SQL и dplyr
-speak мы используем оператор join
.(Здесь приведено несколько примеров нескольких операций, подобных соединению: Как объединить (объединить) фреймы данных (внутренний, внешний, левый, правый) , я рекомендую вам взглянуть и попробовать некоторые из примеровчтобы увидеть, что происходит.)
Нередко промежуточную сводную таблицу хранят в другой переменной и редактируют join
с исходным кадром в другом канале.В данном случае я просто сделал что-то вроде «self- join
» (хотя к моменту перехода к операции соединения оно далеко от «себя»).