【问题标题】:Alternative to Nested If Else Statements替代嵌套 If Else 语句
【发布时间】:2017-07-25 01:47:46
【问题描述】:

我正在使用 R 中的 Retrosheet 棒球数据,并尝试创建一个单独的列(使用 dplyr 中的 mutate 函数),以提醒我现有列中的单个字符串是否以“两次罢工”或“三个球。”例如:

PITCH_SEQ_TX <- c('SSSC', 'FFBB', 'BBSSC', 'BBBSB', 'CBSFFFS')

Retrosheet 开发人员仅列出了一个用于球的字符(“b”),但列出了多个用于罢工的字符(即“c”、“f”、“l”、“m”、“s”、“t”)。因此,如果我想从上面的行中收集哪些序列以两次罢工或三个球开始,我会使用:

PITCH_SEQ_TX_Updated <- mutate(PITCH_SEQ_TX, Cutoff = ifelse(grepl("^BBB", PITCH_SEQ_TX), 
"Three Balls", ifelse(grepl("^SS", updated_PITCH_SEQ_TX), "Two Strikes", 
ifelse(grepl("^FF", PITCH_SEQ_TX), "Two Strikes", "NA"))))

但是两个打击计数(即 cc、cs、ff 等)的不同组合太多,这使我无法在整个数据集上使用嵌套的 if else 语句(我得到一个错误:超过 50 种不同组合时,第 17 行的上下文堆栈溢出警告)。是否有一个替代函数可以让我压缩我现有的代码,无论是使用 ifelse 还是其他可以让我解决这个问题的函数?任何帮助将不胜感激。

【问题讨论】:

  • ?switch 可能会有所帮助
  • case_when,如果你想使用mutate

标签: r if-statement nested-if


【解决方案1】:

您可以使用正则表达式中的一组字符作为罢工标识符,方法是在方括号中指定它们,例如[ABC],这将匹配任何字符ABC。这意味着您不必分别写出每个类别。例如:

grepl("^[CFLMST]{2,}", PITCH_SEQ_TX)
#[1]  TRUE  TRUE FALSE FALSE FALSE
grepl("^B{3,}", PITCH_SEQ_TX)
#[1] FALSE FALSE FALSE  TRUE FALSE

【讨论】:

    【解决方案2】:

    @thelatemail's 答案的基础上,结合@mt1022's 评论使用case_whenmutate,这是一个完整的示例,使用来自stringr 的函数进行文本处理。

    library(dplyr)
    library(stringr)
    
    # make vector of pitch sequence data
    PITCH_SEQ_TX <- c('SSSC', 'FFBB', 'BBSSC', 'BBBSB', 'CBSFFFS')
    
    # make another variable of the number of pitches in each sequence
    # this is just so we have two variables for a df
    NUM_PITCHES <- stringr::str_count(PITCH_SEQ_TX)
    
    # make a df
    BB <- dplyr::tibble(PITCH_SEQ_TX, NUM_PITCHES)
    
    # create the recoded pitch sequence variable - PITCH_SEQ_TX_UPDATED
    BB %>% 
        dplyr::mutate(PITCH_SEQ_TX_UPDATED =
                   dplyr::case_when(
                       stringr::str_detect(string = PITCH_SEQ_TX, pattern = "^[CFLMST]{2,}") ~ "Two strikes",
                       stringr::str_detect(string = PITCH_SEQ_TX, pattern = "^B{3,}") ~ "Three balls"
                       )
        )
    
    # A tibble: 5 x 3
      PITCH_SEQ_TX NUM_PITCHES PITCH_SEQ_TX_UPDATED
             <chr>       <int>                <chr>
    1         SSSC           4          Two strikes
    2         FFBB           4          Two strikes
    3        BBSSC           5                 <NA>
    4        BBBSB           5          Three balls
    5      CBSFFFS           7                 <NA>
    

    【讨论】: