Как обрабатывать нулевые подмножества в R (dplyr)

#r #dplyr #subset

#r #дплыр #подмножество #dplyr

Вопрос:

Я хочу рассчитать средний объем для каждой группы, установив свой фрейм данных между двумя диапазонами дат.

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

Вот повторный:

 product <- c("A","A","A","A","B","B","B","B","C")
date1 <- c("2020-06-20","2020-06-26","2020-08-20","2020-08-22","2020-06-26","2020-06-27","2020-08-21","2020-08-22","2019-06-20")
winA_start <- rep("2020-06-24", times = 9)
winA_end <- rep("2020-06-30", times = 9)
winB_start <- rep("2020-08-19", times = 9)
winB_end <- rep("2020-08-26", times = 9)
vol <- c(200,201,600,800,800,1000,50,100,208)
x <- data.frame(product,date1,winA_start,winA_end,winB_start,winB_end,vol)
x[,2:6] <- lapply(x[,2:6], as.Date)
  

Я хочу запустить следующий код, чтобы вычислить среднее значение как для окна A, так и для окна B

 y <- x %>% group_by(product) %>% mutate(WIN_A_AVG = round(mean(vol[date1 >= winA_start amp; date1 <= winA_end]), digits = 0), WIN_B_AVG = round(mean(vol[date1 >= winB_start amp; date1 <= winB_end]), digit = 0))
  

Это работает по желанию, за исключением продукта C, где date1 не соответствует критериям и поэтому возвращает NaN.

Вместо того, чтобы возвращать NaN, есть ли способ, которым я мог бы отлавливать ошибки такого типа и просто возвращать 0 элегантным способом?

введите описание изображения здесь

Ответ №1:

Если все, что вы хотите сделать, это изменить отсутствующие данные на ноль, вы можете сделать это в том же операторе mutate .

 y <- x %>% 
  group_by(product) %>% 
  mutate(WIN_A_AVG = round(mean(vol[date1 >= winA_start amp; date1 <= winA_end]), digits = 0), 
         WIN_B_AVG = round(mean(vol[date1 >= winB_start amp; date1 <= winB_end]), digit = 0), 
         WIN_A_AVG = case_when(is.na(WIN_A_AVG) ~ 0, 
                               TRUE ~ WIN_A_AVG), 
         WIN_B_AVG = case_when(is.na(WIN_B_AVG) ~ 0, 
                               TRUE ~ WIN_B_AVG))
  

Здесь case_when() функция просто указывает, что когда результат отсутствует, замените его нулем, в противном случае оставьте его прежним. Однако, если вы хотите отслеживать только те случаи, когда наблюдений не было, тогда вам понадобится что-то вроде приведенного ниже кода. Сначала определяется количество наблюдений, затем заменяются только те, которые имеют нулевые наблюдения на 0. Это будет работать лучше, если есть вероятность, что отсутствуют данные, vol такие, что вы хотели бы, чтобы среднее значение возвращалось NA иногда в качестве проверки.

 y <- x %>% 
  group_by(product) %>% 
  mutate(WIN_A_N = length(vol[date1 >= winA_start amp; date1 <= winA_end]), 
         WIN_B_N = length(vol[date1 >= winA_start amp; date1 <= winA_end]), 
         WIN_A_AVG = round(mean(vol[date1 >= winA_start amp; date1 <= winA_end]), digits = 0), 
         WIN_B_AVG = round(mean(vol[date1 >= winB_start amp; date1 <= winB_end]), digit = 0), 
         WIN_A_AVG = case_when(WIN_A_N == 0 ~ 0, 
                               TRUE ~ WIN_A_AVG), 
         WIN_B_AVG = case_when(WIN_B_N == 0 ~ 0, 
                               TRUE ~ WIN_B_AVG)) %>%
  select(-WIN_A_N, -WIN_B_N)
y
# A tibble: 9 x 9
# Groups:   product [3]
#  product date1      winA_start winA_end   winB_start winB_end     vol WIN_A_AVG WIN_B_AVG
#  <chr>   <date>     <date>     <date>     <date>     <date>     <dbl>     <dbl>     <dbl>
#1 A       2020-06-20 2020-06-24 2020-06-30 2020-08-19 2020-08-26   200       201       700
#2 A       2020-06-26 2020-06-24 2020-06-30 2020-08-19 2020-08-26   201       201       700
#3 A       2020-08-20 2020-06-24 2020-06-30 2020-08-19 2020-08-26   600       201       700
#4 A       2020-08-22 2020-06-24 2020-06-30 2020-08-19 2020-08-26   800       201       700
#5 B       2020-06-26 2020-06-24 2020-06-30 2020-08-19 2020-08-26   800       900        75
#6 B       2020-06-27 2020-06-24 2020-06-30 2020-08-19 2020-08-26  1000       900        75
#7 B       2020-08-21 2020-06-24 2020-06-30 2020-08-19 2020-08-26    50       900        75
#8 B       2020-08-22 2020-06-24 2020-06-30 2020-08-19 2020-08-26   100       900        75
#9 C       2019-06-20 2020-06-24 2020-06-30 2020-08-19 2020-08-26   208         0         0