【问题标题】:Compare three (or more) variables in R with ifelse at once with loop使用循环一次将 R 中的三个(或更多)变量与 ifelse 进行比较
【发布时间】:2019-11-01 05:29:36
【问题描述】:

我想比较三个变量。如果都具有相同的结果(例如 0、0、0 和 2、2、2),则返回一个值(例如 'match')。

我试试这个:


df_1 <- data.frame(
  x = c(0, 1, 0, 2, 0), 
  y = c(0, 2, 1, 2, 1), 
  z = c(0, 2, 1, 2, 1)
)


ifelse(df_1$x == df_1$y == df_1$z,  'match', 'not')

错误:“ifelse(df_1$x == df_1$y =="

但它不起作用。谢谢。

【问题讨论】:

    标签: r


    【解决方案1】:

    你需要一个&amp;,所以df_1$x == df_1$y &amp; df_1$y == df_1$z,即x等于yy等于x。您也不需要ifelse 进行这种比较。只需进行比较并将输出添加到您的数据框中:

    df_1$match <- df_1$x == df_1$y & df_1$y == df_1$z
    
    #### OUTPUT ####
      x y z match
    1 0 0 0  TRUE
    2 1 2 2 FALSE
    3 0 1 1 FALSE
    4 2 2 2  TRUE
    5 0 1 1 FALSE
    

    但是,如果您真的想要“匹配”一个“不”,您也可以这样做:

    df_1$match <- ifelse(df_1$x == df_1$y & df_1$y == df_1$z, "matched", "not")
    
    #### OUTPUT ####
    
      x y z match
    1 0 0 0 match
    2 1 2 2   not
    3 0 1 1   not
    4 2 2 2 match
    5 0 1 1   not
    

    根据评论编辑

    对于任意数量的变量,您可以尝试这样的操作,它会检查 unique 是否只返回一个值,即所有变量都相等:

    df_1$match <- apply(df_1, 1, function(r) length(unique(r)) == 1)
    

    【讨论】:

    • 有没有循环的替代方案(例如lapplyifelse)?
    • 示例:lapply(X = df_1, FUN = function(x) { ifelse(x == x, 'match', 'not') })
    • @neves 可能是的,但它不一定是更好的选择。以上使用矢量化,因此它比使用*applys 之一更简单且可能更快。
    • *apply 函数会是什么样子?假设我有一个包含 10 个变量的数据集进行比较。
    • 是的。因为以这种方式比较许多变量非常费力。
    【解决方案2】:

    如果你有大量的变量,你可以这样做:

    df_1$match <- c("match", "no match")[apply(df_1, 1, function(x) length(unique(x)) != 1) + 1]
    df_1
    
      x y z    match
    1 0 0 0    match
    2 1 2 2 no match
    3 0 3 1 no match
    4 2 2 2    match
    5 0 1 1 no match
    

    【讨论】:

      【解决方案3】:

      This post 提供了多种方法来测试向量的所有元素是否相同。由于数据框是向量列表,因此您可以选择其中一种方法,并使用*apply()purrr 或循环之一将其应用于您的数据框。

      这是purrr 的一个选项:

      library(purrr)
      
      df_1$comparison <- map_chr(as.data.frame(t(df_1)), ~ ifelse(
        length(unique(.x)) == 1, 'match', 'not'))
      

      输出:

        x y z comparison
      1 0 0 0      match
      2 1 2 2        not
      3 0 1 1        not
      4 2 2 2      match
      5 0 1 1        not
      

      【讨论】:

        【解决方案4】:

        你也可以使用rowSums():

        rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1])
        
        [1]  TRUE FALSE FALSE  TRUE FALSE
        

        它检查从第二列开始的列是否与第一列相同。如果它们都相同,则返回 TRUE 值。

        如果您需要match/not 结果:

        ifelse(rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1]), "match", "not")
        

        【讨论】:

          【解决方案5】:

          您可以尝试ifelseapply,并使用unique 来查看是否匹配:

          df$match <- apply(df, 1, function(x) ifelse(length(unique(x))==1, 'match','not'))
          

          【讨论】:

            【解决方案6】:

            这是Reduce()的一种方法

            n_cols <- length(df_1)
            
            Reduce(`&`,
                   lapply(seq_len(n_cols - 1),
                          function(j) df_1[[j]] == df_1[[j+1]])
                   )
            

            这是评估TRUEFALSE 的一些答案的表现:

            # A tibble: 4 x 13
              expression                                                 min  median
              <bch:expr>                                             <bch:t> <bch:t>
            1 Reduce_way                                              47.7us  50.5us
            2 rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1]) 159.6us 168.6us
            3 apply(df_1, 1, function(x) length(unique(x)) == 1)     150.6us 158.1us
            4 df_1[[1]] == df_1[[2]] & df_1[[2]] == df_1[[3]]         27.5us  29.6us
            

            性能取决于被评估的列和行的数量。例如 100,000 x 3:

            df_1 <- as.data.frame(replicate(3, sample(3, 100000, replace = T)))
            
              expression                                                  min  median
              <bch:expr>                                             <bch:tm> <bch:t>
            1 Reduce_way                                              931.5us  1.13ms
            2 rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1])  10.96ms 12.69ms
            3 apply(df_1, 1, function(x) length(unique(x)) == 1)        1.01s   1.01s
            4 df_1[[1]] == df_1[[2]] & df_1[[2]] == df_1[[3]]         894.8us  1.06ms
            
            # following is used from here on out instead of writing out df_1[[1]] == ...
            
            n_cols <- length(df_1)
            eval_parse <- paste(
              apply(matrix(rep(seq_len(n_cols), c(1, rep(2, n_cols - 2), 1)), 2),
                    2, 
                    function(cols) paste0("df_1[[", cols, "]]", collapse = ' == ')
              ),
              collapse = ' & '
            )
            
            ## for 100 x 1000 data.frame
            
            df_1 <- as.data.frame(replicate(1000, sample(3, 100, replace = T)))
            
            # A tibble: 4 x 13
              expression                                                min median `itr/sec`
              <bch:expr>                                             <bch:> <bch:>     <dbl>
            1 Reduce_way                                             15.9ms 16.3ms      60.9
            2 rowSums(df_1[, -1] == df_1[, 1]) == length(df_1[, -1]) 16.5ms 17.1ms      58.1
            3 apply(df_1, 1, function(x) length(unique(x)) == 1)     10.4ms 10.7ms      92.4
            4 eval(parse(text = eval_parse))                         20.1ms 20.6ms      47.4
            

            【讨论】:

              【解决方案7】:

              类似于@tmfmnk 的回答(根据@Cole 的评论更新):

              ifelse(rowMeans(df_1 == df_1[, 1]) == 1, 'match', 'not')
              #[1] "match" "not"   "not"   "match" "not" 
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多