С nest
и map
вы можете сделать следующее:
library(tidyverse)
d %>%
group_by(id) %>%
nest() %>%
mutate(cx = map_dbl(data, ~ sum(select(.x, starts_with("c")) * select(.x, starts_with("x")))))
# A tibble: 2 x 3
# id data cx
# <int> <list> <dbl>
# 1 1 <tibble [1 x 7]> 44
# 2 2 <tibble [1 x 7]> 62
В качестве альтернативы вы можете использовать do
, чтобы в качестве входных данных можно было использовать кадр данных:
d %>%
group_by(id) %>%
do(mutate(., cx = sum(select(., starts_with("c")) * select(., starts_with("x")))))
# A tibble: 2 x 9
# Groups: id [2]
# id name c1 c2 c3 x1 x2 x3 cx
# <int> <fct> <int> <int> <int> <int> <int> <int> <int>
# 1 1 a 3 5 2 1 7 3 44
# 2 2 b 4 6 3 2 8 2 62
Чтобы убедиться, что выбраны правильные продукты (то есть x1 * c1, а не x1 * c2), вы можете сначала извлечь максимальное число, которое доступно как для x, так и для c, а затем использовать это для получения правильного соответствия столбца:
col_numbers <- d %>% select(matches("^(x|c)")) %>% names() %>% parse_number()
max_col_number <- which.max(col_numbers[duplicated(col_numbers)])
d %>%
group_by(id) %>%
do(mutate(., cx = sum(select(., str_c("c", seq_len(max_col_number))) * select(., str_c("x", seq_len(max_col_number))))))
Или вы можете сначала расположить столбцы, а затем использовать подход сверху:
d <- select(d, id, name, sort(current_vars()))
d %>%
group_by(id) %>%
do(mutate(., cx = sum(select(., starts_with("c")) * select(., starts_with("x")))))