rowwise () дает ошибку с использованием mean () и sum ()

Я пытаюсь получить среднее значение () и сумму () для определенных столбцов по строкам. Этот код создаст набор данных:

library(tidyverse)

test_data <- tibble(part_id = 1:5,
                      a_1 = c("a", "b", "c", "d", "a"),
                      a_2 = c("b", NA, "b", "a", "d"),
                      a_3 = c("b", "b", "d", "d", "a"))


test_data <- test_data %>%
  mutate_at(vars(a_1, a_2), .funs = list(scored = ~case_when(
    . == "a" | . == "b" ~ 1,
    . == "c" ~ 0,
    . == "d" ~ -100)))

Если я попытаюсь использовать rowSums () или rowMeans (), я получу правильный ответ:

library(tidyverse)

test_data <- test_data %>%
  mutate(a_total = rowSums(dplyr::select(., contains("scored")), na.rm = TRUE),
         a_mean = rowMeans(dplyr::select(., contains("scored")), na.rm = TRUE))

Но если попытаться использовать rowwise (), за которым следует sum () или mean (), это не сработает:

library(tidyverse)

test_data <- test_data %>%
  rowwise() %>%
  mutate(a_total = base::sum(dplyr::select(., contains("scored")), na.rm = TRUE),
         a_mean = base::mean(dplyr::select(., contains("scored")), na.rm = TRUE)) %>%
  ungroup()

Для sum () он дает общую сумму, эффективно игнорируя rowwise (), а для mean () все ответы - NA, и я получаю это предупреждение для каждой строки:

Warning messages:
1: In mean.default(dplyr::select(., contains("scored")), na.rm = TRUE) :
  argument is not numeric or logical: returning NA

Я также попробовал эту модификацию, включив функцию c (), как если бы вы перечисляли каждый столбец. Это привело к следующей ошибке:

library(tidyverse)

test_data <- test_data %>%
  rowwise() %>%
  mutate(a_total = base::sum(c(dplyr::select(., contains("scored"))), na.rm = TRUE),
         a_mean = base::mean(c(dplyr::select(., contains("scored"))), na.rm = TRUE)) %>%
  ungroup()

Error in base::sum(c(dplyr::select(., contains("scored"))), na.rm = TRUE) : 
  invalid 'type' (list) of argument

Как я могу заставить эту работу работать с rowwise ()? Почему это так отличается от обычного и от rowSums () или rowMeans ()?

Я ценю любую проницательность!


person J.Sabree    schedule 05.04.2020    source источник
comment
Вы фактически передаете список sum и mean   -  person Rohit    schedule 05.04.2020


Ответы (2)


Проблема в том, что rowwise выполняет группировку по строкам, а sum, mean и т. Д. Работают с vectors. По сути, это применяется к одной строке data.frame. Обернув unlist, он преобразуется из data.frame в vector

library(dplyr)
test_data <- test_data %>%
                  rowwise() %>%
                  mutate(a_total = base::sum(unlist(dplyr::select(., 
                               contains("scored")), recursive = FALSE), na.rm = TRUE),
                         a_mean = base::mean(unlist(dplyr::select(., 
                               contains("scored")), recursive = FALSE), na.rm = TRUE)) %>%
                   ungroup()

Или используйте pmap

library(purrr)
test_data  %>%
   mutate(a_total = pmap_dbl(select(., contains("scored")),
                    ~ sum(c(...), na.rm = TRUE)),
          a_mean =  pmap_dbl(select(., contains("scored")),
                    ~ mean(c(...), na.rm = TRUE)))
person akrun    schedule 05.04.2020
comment
это заставляет его работать, но дает только общую сумму и большое среднее значение, а не для каждой строки - person J.Sabree; 05.04.2020
comment
Можете ли вы попробовать подход pmap - person akrun; 05.04.2020
comment
да, мне было более любопытно узнать, почему он не работает с rowwise (), но ваш комментарий выше объясняет, почему он не работает. Я просто удивлен, что нет обходного пути! - person J.Sabree; 05.04.2020
comment
@ J.Sabree, проблема в том, что unlist удалит атрибуты и получит весь столбец. Возможно ли, что мы можем использовать do? rowwise в любом случае не так эффективен - person akrun; 05.04.2020

Вот еще один подход, если вы хотите придерживаться rowwise(), который использует {rlang} для захвата переменных, которые вы хотите суммировать и усреднить:

library(dplyr)

test_data <- tibble(part_id = 1:5,
                    a_1 = c("a", "b", "c", "d", "a"),
                    a_2 = c("b", NA, "b", "a", "d"),
                    a_3 = c("b", "b", "d", "d", "a"))


test_data <- test_data %>%
  mutate_at(vars(a_1, a_2), .funs = list(scored = ~case_when(
    . == "a" | . == "b" ~ 1,
    . == "c" ~ 0,
    . == "d" ~ -100)))


# Get the names of the variables you want
vars <- test_data %>% select(contains("scored")) %>% names()

# Use `rlang` so that `dplyr` will recognize the variable names
test_data %>%
  rowwise() %>%
  mutate(a_sum = sum(c(!!!rlang::syms(vars)), na.rm = TRUE),
         a_mean = mean(c(!!!rlang::syms(vars)), na.rm = TRUE)) %>% 
  ungroup()
#> # A tibble: 5 x 8
#>   part_id a_1   a_2   a_3   a_1_scored a_2_scored a_sum a_mean
#>     <int> <chr> <chr> <chr>      <dbl>      <dbl> <dbl>  <dbl>
#> 1       1 a     b     b              1          1     2    1  
#> 2       2 b     <NA>  b              1         NA     1    1  
#> 3       3 c     b     d              0          1     1    0.5
#> 4       4 d     a     d           -100          1   -99  -49.5
#> 5       5 a     d     a              1       -100   -99  -49.5

Создано 5 апреля 2020 г. пакетом REPEX (v0.3.0)

person paqmo    schedule 05.04.2020