【问题标题】:create new column with mutate() when value in any of several other columns is TRUE (or 1)当其他几个列中的任何一个为 TRUE(或 1)时,使用 mutate() 创建新列
【发布时间】:2021-02-05 00:52:49
【问题描述】:

我有一个包含 5 列的数据框 (my_dataframe)。都有 0 或 1 个值。我想创建一个名为 cn7_any 的新列,当 2:5 列中的任何值为 ==1 时,该列的值应为 1。

structure(list(cn7_normal = c(1L, 1L, 1L, 1L, 1L, 1L), 
    cn7_right_paralysis_central = c(0L, 0L, 0L, 0L, 0L, 0L), 
    cn7_right_paralysis_peripheral = c(0L, 0L, 0L, 0L, 0L, 0L), 
    cn7_left_paralysis_central = c(0L, 0L, 0L, 0L, 0L, 0L), 
    cn7_left_paralysis_peripheral = c(0L, 0L, 0L, 0L, 0L, 0L)), 
    row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame"
))
> head(my_dataframe)
# A tibble: 6 x 5
  cn7_normal cn7_right_paralysis_cen… cn7_right_paralysis_perip… cn7_left_paralysis_cen… cn7_left_paralysis_peri…
       <int>                    <int>                      <int>                   <int>                    <int>
1          1                        0                          0                       0                        0
2          1                        0                          0                       0                        0

我可以用 case_when() 成功地做到这一点:

my_dataframe<-my_dataframe%>%
        mutate(cn7_paralisis_any=case_when(cn7_right_paralysis_central==1 ~ 1,
                                           cn7_right_paralysis_peripheral==1 ~ 1,
                                           cn7_left_paralysis_central==1 ~ 1,
                                           cn7_left_paralysis_peripheral==1 ~ 1,
                                           TRUE ~ 0)
                )

虽然它有效,但我想知道是否有更简单、更简洁的解决方案。我觉得我应该以某种方式使用 any() 。有什么想法吗?

【问题讨论】:

    标签: r dplyr any


    【解决方案1】:

    你的数据全为零,所以我换几个来证明这一点。

    rowSums(my_dataframe[,2:5]) > 0
    # [1] FALSE  TRUE FALSE  TRUE FALSE FALSE
    +(rowSums(my_dataframe[,2:5]) > 0)
    # [1] 0 1 0 1 0 0
    
    my_dataframe$cn7_any <- +(rowSums(my_dataframe[,2:5]) > 0)
    

    dplyr内,

    my_dataframe %>%
      mutate(cn7_any = rowSums(across(-cn7_normal, ~ . > 0)) > 0)
    # # A tibble: 6 x 6
    #   cn7_normal cn7_right_paralysis_central cn7_right_paralysis_peripheral cn7_left_paralysis_central cn7_left_paralysis_peripheral cn7_any
    #        <int>                       <int>                          <int>                      <int>                         <int> <lgl>  
    # 1          1                           0                              0                          0                             0 FALSE  
    # 2          1                           0                              0                          0                             1 TRUE   
    # 3          1                           0                              0                          0                             0 FALSE  
    # 4          1                           0                              0                          1                             0 TRUE   
    # 5          1                           0                              0                          0                             0 FALSE  
    # 6          1                           0                              0                          0                             0 FALSE  
    

    您正在做的似乎是logical,而不是数字,但如果您想要数字,只需使用上述+(.) 技巧:

    my_dataframe %>%
      mutate(cn7_any = +(rowSums(across(-cn7_normal, ~ . > 0)) > 0))
    

    【讨论】:

      【解决方案2】:
      my_dataframe$cn7_any <- apply(my_dataframe[ , 2:5], 1, max)
      

      【讨论】:

        【解决方案3】:

        类似于Using any() vs | in dplyr::mutate

        我还更改了您数据集中的一些数字。

        V2:使用或|

        V3:使用mutate 之前的dplyr::rowwise() 按行有效地对输入进行分组,然后使用all() 函数(all 查看整个向量,这就是您得到意外结果的原因)

        my_dataframe<-structure(list(cn7_normal = c(1L, 1L, 1L, 1L, 1L, 1L), 
            cn7_right_paralysis_central         = c(0L, 0L, 0L, 0L, 0L, 0L), 
            cn7_right_paralysis_peripheral      = c(1L, 0L, 0L, 0L, 0L, 0L), 
            cn7_left_paralysis_central          = c(0L, 1L, 0L, 0L, 0L, 0L), 
            cn7_left_paralysis_peripheral       = c(0L, 0L, 0L, 0L, 0L, 0L)), 
            row.names = c(NA, -6L), 
            class = c("tbl_df", "tbl", "data.frame"))
        
        my_dataframe%>%
          rowwise() %>% ### rowwise ###
          mutate(cn7_paralisis_any=case_when(cn7_right_paralysis_central==1 ~ 1,
                                             cn7_right_paralysis_peripheral==1 ~ 1,
                                             cn7_left_paralysis_central==1 ~ 1,
                                             cn7_left_paralysis_peripheral==1 ~ 1,
                                             TRUE ~ 0),
                 cn7_v2=(cn7_right_paralysis_central|cn7_right_paralysis_peripheral|cn7_left_paralysis_central|cn7_left_paralysis_peripheral),
                 cn7_v3=any(cn7_right_paralysis_central ,cn7_right_paralysis_peripheral, cn7_left_paralysis_central, cn7_left_paralysis_peripheral)
          ) %>% 
          select(cn7_paralisis_any,cn7_v2,cn7_v3)
        
        
        # A tibble: 6 x 3
        # Rowwise: 
        #  cn7_paralisis_any cn7_v2 cn7_v3
        #              <dbl> <lgl>  <lgl> 
        #1                 1 TRUE   TRUE  
        #2                 1 TRUE   TRUE  
        #3                 0 FALSE  FALSE 
        #4                 0 FALSE  FALSE 
        #5                 0 FALSE  FALSE 
        #6                 0 FALSE  FALSE 
        

        【讨论】:

          【解决方案4】:

          我现在在这种情况下使用dplyr::if_anydplyr::if_all。我认为每当我们必须在 dplyr 中执行此类逐行逻辑操作时,它都会使代码非常清晰易读。

          对于这种特殊情况,我现在会使用:

          library(dplyr)
          
          my_dataframe %>%
               mutate(cn7_paralisis_any = +if_any(across(-cn7_normal)))
          

          【讨论】:

            猜你喜欢
            • 2023-01-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多