【问题标题】:subset rows with (1) ALL and (2) ANY columns larger than a specific value具有 (1) ALL 和 (2) ANY 列大于特定值的子集行
【发布时间】:2021-02-25 19:31:25
【问题描述】:

我有一个带有 id 列的数据框和一些(可能很多)带有值的列,这里是 'v1'、'v2':

df <- data.frame(id = c(1:5), v1 = c(0,15,9,12,7), v2 = c(9,32,6,17,11))
#   id v1 v2
# 1  1  0  9
# 2  2 15 32
# 3  3  9  6
# 4  4 12 17
# 5  5  7 11
  1. 如何提取所有值都大于某个值的行,比如 10,应该返回:

    #   id v1 v2
    # 2  2 15 32
    # 4  4 12 17
    
  2. 如何提取任何(至少一个)值大于 10 的行:

    #   id v1 v2
    # 2  2 15 32
    # 4  4 12 17
    # 5  5  7 11
    

【问题讨论】:

    标签: r subset r-faq


    【解决方案1】:

    请参阅函数 all()any() 分别获取问题的第一部分和第二部分。 apply() 函数可用于在行或列上运行函数。 (MARGIN = 1 是行,MARGIN = 2 是列,等等)。请注意,在进行比较时,我在 df[, -1] 上使用 apply() 来忽略 id 变量。

    第 1 部分:

    > df <- data.frame(id=c(1:5), v1=c(0,15,9,12,7), v2=c(9,32,6,17,11))
    > df[apply(df[, -1], MARGIN = 1, function(x) all(x > 10)), ]
      id v1 v2
    2  2 15 32
    4  4 12 17
    

    第 2 部分:

    > df[apply(df[, -1], MARGIN = 1, function(x) any(x > 10)), ]
      id v1 v2
    2  2 15 32
    4  4 12 17
    5  5  7 11
    

    要查看发生了什么,x &gt; 10 为每一行返回一个逻辑向量(通过 apply() 指示每个元素是否大于 10。all() 返回 TRUE 如果 all输入向量的元素是 TRUEFALSE 否则。any() 返回 TRUE 如果输入中的元素 任何TRUEFALSE 如果都是 @987654341 @。

    然后我使用apply() 调用产生的逻辑向量

    > apply(df[, -1], MARGIN = 1, function(x) all(x > 10))
    [1] FALSE  TRUE FALSE  TRUE FALSE
    > apply(df[, -1], MARGIN = 1, function(x) any(x > 10))
    [1] FALSE  TRUE FALSE  TRUE  TRUE
    

    到子集df(如上所示)。

    【讨论】:

      【解决方案2】:

      这可以使用 apply 和边距 1 来完成,它将对每一行应用一个函数。检查给定行的函数是

      function(row) {all(row > 10)}
      

      所以提取行本身的方法是

      df[apply(df, 1, function(row) {all(row > 10)}),]
      

      【讨论】:

      • 等等,你想做all(row[-1] &gt; 10) 不考虑id 列。或者在df[-1]上应用函数。
      【解决方案3】:

      一个选项是逐行循环(例如使用apply)并使用anyall,正如其他两个答案中所建议的那样。但是,这对于大型数据帧可能效率低下。

      矢量化方法是使用rowSums 来确定每行中与您的条件匹配的值的数量,并根据该数量进行过滤。

      (1) 过滤到所有值至少为10的行时,这与过滤到一行中小于或等于10的值的个数为0的情况相同:

      df[rowSums(df[,-1] <= 10) == 0,]
      #   id v1 v2
      # 2  2 15 32
      # 4  4 12 17
      

      (2) 类似地,rowSums 可以很容易地用于计算任何(至少一个)值大于 10 的行:

      df[rowSums(df[,-1] > 10) > 0,]
      #   id v1 v2
      # 2  2 15 32
      # 4  4 12 17
      # 5  5  7 11
      

      输入越大,加速效果越明显:

      set.seed(144)
      df <- matrix(sample(c(1, 10, 20), 3e6, replace=TRUE), ncol=3)
      system.time(df[apply(df[, -1], MARGIN = 1, function(x) all(x > 10)), ])
      #    user  system elapsed 
      #   1.754   0.156   2.102 
      system.time(df[rowSums(df[,-1] <= 10) == 0,])
      #    user  system elapsed 
      #    0.04    0.01    0.05 
      

      【讨论】:

        【解决方案4】:

        dplyr 等效项如下

        library(dplyr)
        
        #ANY
        df %>% rowwise() %>%
          filter(any(across(starts_with("v"), ~ sum((. > 10)))))
        # A tibble: 3 x 3
        # Rowwise: 
             id    v1    v2
          <int> <dbl> <dbl>
        1     2    15    32
        2     4    12    17
        3     5     7    11
        
        
        #ALL
        df %>% rowwise() %>%
          filter(all(across(starts_with("v"), ~ sum((. > 10)))))
        
        # A tibble: 2 x 3
        # Rowwise: 
             id    v1    v2
          <int> <dbl> <dbl>
        1     2    15    32
        2     4    12    17
        
        

        【讨论】:

          猜你喜欢
          • 2017-01-10
          • 1970-01-01
          • 2017-12-27
          • 2021-07-12
          • 2016-07-29
          • 2013-06-18
          • 2020-10-27
          • 2023-04-08
          • 1970-01-01
          相关资源
          最近更新 更多