in mutate (dplyr) - обрабатывает несколько столбцов как вектор строки - PullRequest
0 голосов
/ 13 января 2019

У меня есть фрейм данных с несколькими столбцами, которые представляют коэффициенты в определенном уравнении. Я хочу оценить это уравнение и добавить его к кадру данных (например, построчное вычисление). но для оценки уравнения мне нужны все коэффициенты в виде вектора строки. Вот пример:

d = data.frame(id = 1:2,name=c("a","b"),
               c1 = 3:4,c2=5:6,c3=2:3,
               x1=1:2,x2=7:8,x3=3:2)

Мне нужно оценить c1 * x1 + c2 * x2 + x3 * x3, но вводить точное уравнение нецелесообразно. в реальном случае их десятки. В идеале я хотел бы выбрать их и рассматривать их как векторы строк, что-то вроде этого:

# not a real code, but a wishful thinkg
d %>% mutate(result = sum((select(starts_with(c)) %>% as.vector)*
                           select(starts_with(x)) %>% as.vector)
                      )
             )

Это, конечно, не так, но мне интересно, знаете ли вы какой-либо способ обработки группы столбцов как вектора строки при выполнении вычисления строки за строкой, как при mutate.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 13 января 2019

С 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")))))
0 голосов
/ 13 января 2019

Одной из идей является gather фрейм данных следующим образом. Результат находится в столбце CX.

library(tidyverse)

d2 <- d %>%
  gather(Type, Value, -id, -name) %>%
  separate(Type, into = c("Letter", "Number"), sep = 1) %>%
  spread(Letter, Value) %>%
  mutate(CX = c * x) %>%
  group_by(name) %>%
  summarize(CX = sum(CX))
d2
# # A tibble: 2 x 2
#   name     CX
#   <fct> <int>
# 1 a        44
# 2 b        62

А вот вариант с dplyr. Однако вы должны убедиться, что порядок столбцов правильный, если вы хотите использовать это решение.

dc <- d %>% select(starts_with("c"))
dx <- d %>% select(starts_with("x"))
d3 <- dc * dx 
d4 <- bind_cols(d %>% select(id, name), d3) %>% mutate(CX = rowSums(d3))
d4
#   id name c1 c2 c3 CX
# 1  1    a  3 35  6 44
# 2  2    b  8 48  6 62

А вот базовый эквивалент R приведенного выше кода.

dc <- d[, grepl("^c", names(d))]
dx <- d[, grepl("^x", names(d))]
d3 <- dc * dx 
d3$CX <- rowSums(d3)
d4 <- cbind(d[, c("id", "name")], d3)
d4
#   id name c1 c2 c3 CX
# 1  1    a  3 35  6 44
# 2  2    b  8 48  6 62
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...