包含大于特定值的 (1) ALL 和 (2) ANY 列的子集行

subset rows with (1) ALL and (2) ANY columns larger than a specific value

提问人:Rock 提问时间:3/25/2012 最后编辑:HenrikRock 更新时间:2/25/2021 访问量:43510

问:

我有一个带有 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. 如何提取 ANY(至少一个)值大于 10 的行:

    #   id v1 v2
    # 2  2 15 32
    # 4  4 12 17
    # 5  5  7 11
    
子集 R-FAQ

评论


答:

8赞 bnaul 3/25/2012 #1

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

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

因此,提取行本身的方法是

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

评论

2赞 flodel 3/25/2012
等等,你要不要考虑该列。或将该函数应用于 。all(row[-1] > 10)iddf[-1]
23赞 Gavin Simpson 3/25/2012 #2

分别查看函数和问题的第一部分和第二部分。该函数可用于在行或列上运行函数。(是行,是列等)。注意:在进行比较时,我使用 on 忽略该变量。all()any()apply()MARGIN = 1MARGIN = 2apply()df[, -1]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

为了查看发生了什么,为每行返回一个逻辑向量(通过指示每个元素是否大于 10。 如果输入向量的所有元素都为 ,则返回,否则返回。 如果输入中的任何元素是 ,如果所有元素都是 ,则返回 。x > 10apply()all()TRUETRUEFALSEany()TRUETRUEFALSEFALSE

然后,我使用调用产生的逻辑向量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

4赞 josliber 8/12/2017 #3

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

矢量化方法是用于确定每行中与您的条件匹配的值数,并基于该值进行筛选。rowSums

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

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

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

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 
1赞 AnilGoyal 2/25/2021 #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