используя функцию суммы в dplyr mutate - PullRequest
1 голос
/ 30 марта 2019

Я пытаюсь использовать функцию суммы внутри функции изменения dplyr.Однако я получаю неожиданные результаты.Ниже приведен код для воспроизведения проблемы

chk1 <- data.frame(ba_mat_x=c(1,2,3,4),ba_mat_y=c(NA,2,NA,5))

Я использовал приведенный ниже код для создания другого столбца, который суммирует 2 вышеупомянутых столбца

chk2 <- chk1 %>% dplyr::mutate(ba_mat=sum(ba_mat_x+ba_mat_y,na.rm = T))

Я использовал na.rm=T, потому что яиметь NA s в переменной ba_mat_y.Я получил следующий результат:

        ba_mat_x ba_mat_y ba_mat
   1        1       NA     13
   2        2        2     13
   3        3       NA     13
   4        4        5     13

Однако ожидаемый результат -

      ba_mat_x ba_mat_y ba_mat
1        1       NA     1
2        2        2     4
3        3       NA     3
4        4        5     9

Ответы [ 3 ]

2 голосов
/ 30 марта 2019

Вы хотите rowSums, чтобы получить сумму столбцов для каждой строки.

> chk1 %>% dplyr::mutate(ba_mat = rowSums(., na.rm=T))

  ba_mat_x ba_mat_y ba_mat
1        1       NA      1
2        2        2      4
3        3       NA      3
4        4        5      9

Ваша другая формулировка (sum(ba_mat_x+ba_mat_y,na.rm = T))) означает:

  • первое выполнение chk1$ba_mat_x + chk1$ba_mat_y: 1 + NA, 2 + 2, 3 + NA, 4 + 5, что приводит к NA, 4, NA, 9
  • , затем принимает sum(na.rm=T) того, что составляет 13
1 голос
/ 30 марта 2019

Мы можем использовать rowSums из base R

chk1$ba_mat <- rowSums(chk1, na.rm = TRUE)
chk1
#   ba_mat_x ba_mat_y ba_mat
#1        1       NA      1
#2        2        2      4
#3        3       NA      3
#4        4        5      9

Или использовать tidverse при сохранении исходных столбцов как таковых

library(tidyverse)
chk1 %>% 
    mutate(ba_mat  = replace(., is.na(.), 0) %>%
                     reduce(`+`))
#    ba_mat_x ba_mat_y ba_mat
#1        1       NA      1
#2        2        2      4
#3        3       NA      3
#4        4        5      9

Или с case_when

chk1 %>% 
    mutate_if(is.numeric, list(new = ~case_when(is.na(.) ~ 0,
                TRUE ~ .))) %>%
    transmute(!!! rlang::syms(names(chk1)), ba_mat = ba_mat_x_new + ba_mat_y_new)
#   ba_mat_x ba_mat_y ba_mat
#1        1       NA      1
#2        2        2      4
#3        3       NA      3
#4        4        5      9
1 голос
/ 30 марта 2019

Если у нас есть несколько столбцов и мы хотим суммировать только ограниченные столбцы, мы можем заменить их на 0, а затем добавить столбцы

library(dplyr)

chk1 %>%
  mutate_at(vars(ba_mat_x,ba_mat_y), ~ replace(., is.na(.), 0)) %>%
  mutate(ba_mat = ba_mat_x + ba_mat_y)

#  ba_mat_x ba_mat_y ba_mat
#1        1        0      1
#2        2        2      4
#3        3        0      3
#4        4        5      9

Мы также можем использовать replace_na из tidyr, что делает то же самое.

chk1 %>%
  mutate_at(vars(ba_mat_x, ba_mat_y), tidyr::replace_na, 0) %>%
  mutate(ba_mat = ba_mat_x + ba_mat_y)

Если мы хотим использовать sum, другой вариант - использовать purrr 'pmap или pmap_dbl, где мы можем теперь передать список столбцов для добавления, а затем использовать sum.

chk1 %>%
  mutate(ba_mat = purrr::pmap_dbl(list(ba_mat_x, ba_mat_y), sum, na.rm = TRUE)) 

#  ba_mat_x ba_mat_y ba_mat
#1        1       NA      1
#2        2        2      4
#3        3       NA      3
#4        4        5      9

В данном конкретном случае мы также можем использовать map2_dbl

chk1 %>%
  mutate(ba_mat = purrr::map2_dbl(ba_mat_x, ba_mat_y, sum, na.rm = TRUE))

Это также будет работать, так как у нас есть только два столбца, но в случае, если есть больше столбцов, лучше / безопаснее использовать параметр pmap.


Более того, что касается вашей попытки, она сработает, если вы добавите к ней rowwise. rowwise, как следует из названия, выполняет все операции построчно.

chk1 %>% 
  rowwise() %>%
  mutate(ba_mat = sum(ba_mat_x, ba_mat_y, na.rm = T))

Но rowwise обычно медленнее.

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