Использование мутирования по ряду над подмножеством столбцов - PullRequest
0 голосов
/ 31 января 2019

Я пытаюсь создать новый столбец, который будет содержать результат вычислений, выполненных по строке над подмножеством столбцов таблицы, и добавить этот новый столбец к существующему столбцу.Примерно так:

df <- tibble(
ID = c("one", "two", "three"),
A1 = c(1, 1, 1),
A2 = c(2, 2, 2),
A3 = c(3, 3, 3)
)

Я действительно хочу сделать dplyr-эквивалент этого кода из базы R:

df$SumA <- rowSums(df[,grepl("^A", colnames(df))])

Моя проблема в том, что это не работает:

df %>% 
select(starts_with("A")) %>% 
mutate(SumA = rowSums(.))
    # some code here

... потому что я избавился от столбца «ID», чтобы позволить mutate запускать rowSums над другими (числовыми) столбцами.Я пытался cbind или bind_cols в трубе после mutate, но это не работает.Ни один из вариантов мутации не работает, потому что они работают на месте (внутри каждой ячейки таблицы, а не поперек столбцов, даже со строкой).

Это работает, но не поражает меня какэлегантное решение:

df %>% 
mutate(SumA = rowSums(.[,grepl("^A", colnames(df))]))

Существует ли какое-либо решение на основе тидиверса, которое не требует grepl или квадратных скобок, а только содержит более стандартные глаголы и параметры dplyr?

Мой ожидаемый результат такой:

df_out <- tibble(
ID = c("one", "two", "three"),
A1 = c(1, 1, 1),
A2 = c(2, 2, 2),
A3 = c(3, 3, 3),
SumA = c(6, 6, 6)
)

Бест кДж

Ответы [ 5 ]

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

Вы можете вкладывать и использовать rowSums на вложенных столбцах:

library(tidyverse)
df %>% nest(-ID) %>%
  mutate(SumA = map_dbl(data,rowSums)) %>%
  unnest

# # A tibble: 3 x 5
#      ID  SumA    A1    A2    A3
#   <chr> <dbl> <dbl> <dbl> <dbl>
# 1   one     6     1     2     3
# 2   two     6     1     2     3
# 3 three     6     1     2     3

Или этот вариант на подходе pmap:

df %>% mutate(SumA = pmap_dbl(.[-1],sum))
# # A tibble: 3 x 5
#      ID    A1    A2    A3  SumA
#   <chr> <dbl> <dbl> <dbl> <dbl>
# 1   one     1     2     3     6
# 2   two     1     2     3     6
# 3 three     1     2     3     6

И показать, что базаиногда проще:

df$SumA <- rowSums(df[-1])
0 голосов
/ 31 января 2019

[обн] Я не заметил, что @Calum использовал почти такой же подход.

Другой возможный способ сделать это:

library(dplyr)
library(purrr)

dat %>%
  mutate(SumA = pmap_dbl(select(., contains('A')), sum))   

Данные:

# dat <- tibble(
#   ID = c("one", "two", "three"),
#   A1 = c(1, 1, 1),
#   A2 = c(2, 2, 2),
#   A3 = c(3, 3, 3)
# )

Выход:

# # A tibble: 3 x 5
#   ID       A1    A2    A3  SumA
#   <chr> <dbl> <dbl> <dbl> <dbl>
# 1 one       1     2     3     6
# 2 two       1     2     3     6
# 3 three     1     2     3     6
0 голосов
/ 31 января 2019

Вот другой подход, который не двигается по строкам, а использует векторизованную природу сложения, и это сложение коммутирует.Это позволяет многократно использовать + с purrr::reduce

library(tidyverse)
df <- tibble(
  ID = c("one", "two", "three"),
  A1 = c(1, 1, 1),
  A2 = c(2, 2, 2),
  A3 = c(3, 3, 3)
)

df %>%
  mutate(
    SumA = reduce(
      .x = select(., starts_with("A")),
      .f = `+`
    )
  )
#> # A tibble: 3 x 5
#>   ID       A1    A2    A3  SumA
#>   <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 one       1     2     3     6
#> 2 two       1     2     3     6
#> 3 three     1     2     3     6

Создано в 2019-01-30 с помощью пакета Представить (v0.2.1)

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

1) Чтобы сделать это с rowSums, попробуйте вложить второй конвейер в mutate следующим образом:

library(dplyr)

df %>% mutate(Sum = select(., starts_with("A")) %>% rowSums)

, давая:

# A tibble: 3 x 5
  ID       A1    A2    A3   Sum
  <chr> <dbl> <dbl> <dbl> <dbl>
1 one       1     2     3     6
2 two       1     2     3     6
3 three     1     2     3     6

2) Альтернатива состоит в том, чтобы преобразовать его в длинную форму и затем суммировать:

library(dplyr)
library(purrr)
library(tidyr)

df %>%
  mutate(Sum = gather(., key, value, -ID) %>% 
               group_by(., ID) %>%
               summarize(sum = sum(value)) %>%
               ungroup %>%
               pull(sum))

, давая:

# A tibble: 3 x 5
  ID       A1    A2    A3   Sum
  <chr> <dbl> <dbl> <dbl> <dbl>
1 one       1     2     3     6
2 two       1     2     3     6
3 three     1     2     3     6
0 голосов
/ 31 января 2019

Вот один из подходов к построчному вычислению в tidyverse с использованием purrr::pmap.Это лучше всего использовать с функциями, которые на самом деле нужно запускать построчно;простое добавление может быть сделано быстрее.Обычно мы используем select для предоставления списка ввода для pmap, что позволяет нам использовать select помощников, таких как starts_with или matches, если вам нужно регулярное выражение.

library(tidyverse)
df <- tibble(
  ID = c("one", "two", "three"),
  A1 = c(1, 1, 1),
  A2 = c(2, 2, 2),
  A3 = c(3, 3, 3)
)

df %>%
  mutate(
    SumA = pmap_dbl(
      .l = select(., starts_with("A")),
      .f = function(...) sum(...)
    )
  )
#> # A tibble: 3 x 5
#>   ID       A1    A2    A3  SumA
#>   <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 one       1     2     3     6
#> 2 two       1     2     3     6
#> 3 three     1     2     3     6

Создано в 2019-01-30 пакетом Представ (v0.2.1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...