Несколько условий if-else с использованием dplyr, пользовательской функции или мурлыканья - PullRequest
0 голосов
/ 26 августа 2018

У меня есть фрейм данных, структура которого похожа на следующую:

set.seed(123)  
df<-data_frame(SectionName = rep(letters[1:2], 50),
               TimeSpentSeconds = sample(0:360, 100, replace = TRUE),
               Correct = sample(0:1, 100, replace = TRUE))

Я хочу суммировать этот фрейм данных, взяв все значения TimeSpentSeconds, которые попадают в определенные диапазоны (меньше 30, между 30-60, между 60-90, ..., больше 180), помечать время как эти диапазоны , сгруппируйте их по SectionName и найдите сумму столбца Correct, чтобы результирующий фрейм данных выглядел (как-то) так:

    TimeGroup             SectionName Correct
   <fct>                 <chr>         <int>
 1 LessThan30Secs        a                 2
 2 LessThan30Secs        b                 3
 3 30-60 Seconds         a                 4
 4 30-60 Seconds         b                 3
 5 60-90 Seconds         a                 2
 6 60-90 Seconds         b                 3
 7 90-120 Seconds        a                 4
 8 90-120 Seconds        b                 0
 9 120-150 Seconds       a                 4
10 120-150 Seconds       b                 0
11 150-180 Seconds       a                 1
12 150-180 Seconds       b                 2
13 GreaterThan180Seconds a                11
14 GreaterThan180Seconds b                11

Мне удалось успешно сделать это с помощью следующего кода if-else, где я все время мутировал в новый столбец с соответствующей меткой, сгруппировал и суммировал:

x <- c("LessThan30Secs", "30-60 Seconds", "60-90 Seconds","90-120 Seconds", 
           "120-150 Seconds", "150-180 Seconds", "GreaterThan180Seconds") 

df %>% 
mutate(TimeGroup = if_else(TimeSpentSeconds >= 0 & TimeSpentSeconds <= 30, "LessThan30Secs",
                if_else(TimeSpentSeconds > 30 & TimeSpentSeconds <= 60, "30-60 Seconds",
                if_else(TimeSpentSeconds > 60 & TimeSpentSeconds <= 90, "60-90 Seconds",
                if_else(TimeSpentSeconds > 90 & TimeSpentSeconds <= 120, "90-120 Seconds",
                if_else(TimeSpentSeconds > 120 & TimeSpentSeconds <= 150, "120-150 Seconds", 
                if_else(TimeSpentSeconds > 150 & TimeSpentSeconds <= 180, "150-180 Seconds",
                if_else(TimeSpentSeconds > 180, "GreaterThan180Seconds", "")))))))) %>%
    mutate(TimeGroup = factor(TimeGroup, levels = x)) %>%
    arrange(TimeGroup) %>%
    group_by(TimeGroup, SectionName) %>%
    summarise(Correct = sum(Correct))

Но, просто должен быть лучший способ сделать это. Я подумал о написании функции, но не очень далеко, потому что я не очень хорош в написании функций.

Есть ли у кого-нибудь идеи относительно более элегантного способа выполнения этого же вывода с помощью метода dplyr, о котором я не думал, написания пользовательской функции, возможно, с использованием пакета purrr в какой-то момент или некоторой другой функции r?

Ответы [ 3 ]

0 голосов
/ 26 августа 2018

Мы можем сделать это легко с помощью cut (или findInterval) вместо нескольких вложенных ifelse операторов

lbls <- c('LessThan30secs', '30-60 Seconds', '60-90 Seconds', 
    '90-120 Seconds', '120-150 Seconds', '150-180 Seconds', 'GreaterThan180Seconds')
df %>% 
    group_by(TimeGroup = cut(TimeSpentSeconds, 
                 breaks = c(seq(0, 180, by = 30), Inf), labels = lbls), 
            SectionName) %>%
   summarise(Correct = sum(Correct)) %>%
   na.omit
0 голосов
/ 27 августа 2018

case_when() будет делать то, что вы хотите. Это аккуратная альтернатива вложенным ifelse() операторам.

library(dplyr)

mutate(df,
       TimeGroup = case_when(
         TimeSpentSeconds >= 0 & TimeSpentSeconds <= 30 ~ "Less Than 30 Secs",
         TimeSpentSeconds > 30 & TimeSpentSeconds <= 60 ~ "30-60 Seconds",
         TimeSpentSeconds > 60 & TimeSpentSeconds <= 90 ~ "60-90 Seconds",
         TimeSpentSeconds > 90 & TimeSpentSeconds <= 120 ~ "90-120 Seconds",
         TimeSpentSeconds > 120 & TimeSpentSeconds <= 150 ~ "120-150 Seconds", 
         TimeSpentSeconds > 150 & TimeSpentSeconds <= 180 ~ "150-180 Seconds",
         TimeSpentSeconds > 180 ~ "Greater Than 180 Seconds",
         TRUE ~ "NA_character_")
)

Последний аргумент является универсальным для записей, которые не соответствуют ни одному из критериев, например, если время как-то меньше 0 секунд.

0 голосов
/ 26 августа 2018
``` r
library(tidyverse)
set.seed(123)
df<-data_frame(SectionName = rep(letters[1:2], 50),
               TimeSpentSeconds = sample(0:360, 100, replace = TRUE),
               Correct = sample(0:1, 100, replace = TRUE))

time_spent_range <- function(value, start, end, interval) {
  end <- end + (end%%interval) # make sure the end value is divisible by the interval
  bins_start <- seq(start, end - interval, by = interval)
  bins_end <- seq(start + interval, end, by = interval)
  bins_tibble <- tibble(bin_start = bins_start, 
                        bin_end = bins_end) %>% 
    mutate(in_bin = if_else((value > bin_start|(value == 0 & bin_start == 0)) 
                            & value <= bin_end,
                            1,
                            0)) %>% 
    filter(in_bin == 1)
  bin <- paste0(as.character(bins_tibble$bin_start[1]), 
                '-', 
                as.character(bins_tibble$bin_end[1]),
                ' Seconds')
  return(bin)
}

df %>% 
  mutate(TimeGroup = map_chr(TimeSpentSeconds, time_spent_range, start = 0, end = max(df$TimeSpentSeconds) , interval = 30))
#> # A tibble: 100 x 4
#>    SectionName TimeSpentSeconds Correct TimeGroup      
#>    <chr>                  <int>   <int> <chr>          
#>  1 a                        103       1 90-120 Seconds 
#>  2 b                        284       0 270-300 Seconds
#>  3 a                        147       0 120-150 Seconds
#>  4 b                        318       1 300-330 Seconds
#>  5 a                        339       0 330-360 Seconds
#>  6 b                         16       1 0-30 Seconds   
#>  7 a                        190       1 180-210 Seconds
#>  8 b                        322       1 300-330 Seconds
#>  9 a                        199       0 180-210 Seconds
#> 10 b                        164       0 150-180 Seconds
#> # ... with 90 more rows
```

Создано в 2018-08-26 пакетом Представ (v0.2.0).

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