【问题标题】:How do you evaluate a set of conditions and create a new column based on a list of columns?您如何评估一组条件并根据列列表创建新列?
【发布时间】:2020-04-24 02:10:02
【问题描述】:

我想在数据框中列出(或过滤)一组名称相似的列,为每一行评估这些列的值,然后使用结果创建一个新列。

现在我正在使用case_when,但我不知道提供一些通配符或已定义列的列表的方法。

我想列出一个列列表或创建一个过滤器,因为我想评估数据框中的几列,而不仅仅是少数几列。当列名彼此非常相似时,在case_when 中拥有一长串列似乎效率不高。

# Dummy data
ignore1 <- c(1, 0, 0)
ignore2 <- c(1, 0, 1)
col1 <- c(0, 1, 0)
col2 <- c(0, 1, 1)
col3 <- c(0, 1, 0)

df <- data.frame(ignore1, ignore2, col1, col2, col3)
df %>% 
  mutate(evaluation = case_when(
    col1 == 0| col1 == 0 | col1 == 0  ~ "Failed",
    TRUE ~ "Passed"
    )
  )

这是预期的结果:

  ignore1 ignore2 col1 col2 col3 evaluation
1       1       1    0    0    0     Failed
2       0       0    1    1    1     Passed
3       0       1    0    1    0     Failed

第 2 行通过的位置,因为 col1col2col3 所有的值为 1

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    我们可以使用rowSums 来提高效率

    i1 <- startsWith(names(df), 'col')
    c( "Failed",  "Passed")[(rowSums(df[i1] == 1) == 3) + 1]
    #[1] "Failed" "Passed" "Failed"
    

    或者另一个base R 有效的选项是Reduce

    c("Failed", "Passed")[Reduce(`&`, df[i1]) +1]
    #[1] "Failed" "Passed" "Failed"
    

    注意:base R 的两个解决方案都很紧凑并且非常高效


    &amp;

    library(dplyr)
    df %>% 
         mutate(evaluation =  c('Failed', 'Passed')[1 + (col1 & col2 & col3)])
    #  ignore1 ignore2 col1 col2 col3 evaluation
    #1       1       1    0    0    0     Failed
    #2       0       0    1    1    1     Passed
    #3       0       1    0    1    0     Failed
    

    或者我们可以在dplyr 中添加rowSums

    df %>%
       mutate(evaluation = c("Failed", "Passed")[(rowSums(.[i1] == 1) == 3) + 1])
    

    注意:这两种解决方案都非常有效,并且不使用任何不需要的包

    或者如果我们需要一些包,那么使用magrittrpurrr

    library(magrittr)
    library(purrr)
    df %>% 
       mutate(evaluation = select(., starts_with('col')) %>% 
                              reduce(`&`) %>%
                              add(1) %>%
                              c("Failed", "Passed")[.])
    #  ignore1 ignore2 col1 col2 col3 evaluation
    #1       1       1    0    0    0     Failed
    #2       0       0    1    1    1     Passed
    #3       0       1    0    1    0     Failed
    

    注意:这里也没有循环遍历行,所以它应该是有效的

    【讨论】:

    • 您能否修改您的回复,以便不引用特定的列名或索引?喜欢col*
    • @DarenEiri 谢谢,我把它改成了startsWith (i1)。你能检查一下这是否适合你
    【解决方案2】:

    如果您想执行逐行操作,我们可以使用 pmap 变体

    library(dplyr)
    library(purrr)
    
    df %>% mutate(result =c("Passed","Failed")[pmap_lgl(select(., starts_with('col')),
                           ~any(c(...) == 0)) + 1])
    
    #  ignore1 ignore2 col1 col2 col3 result
    #1       1       1    0    0    0 Failed
    #2       0       0    1    1    1 Passed
    #3       0       1    0    1    0 Failed
    

    在base R中,我们可以使用apply row-wise :

    cols <- startsWith(names(df), 'col')
    df$Result <- c("Passed", "Failed")[apply(df[cols] == 0, 1, any) + 1]
    

    【讨论】:

      猜你喜欢
      • 2019-09-28
      • 1970-01-01
      • 1970-01-01
      • 2018-10-24
      • 1970-01-01
      • 2020-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多