提问人:Rock 提问时间:3/25/2012 最后编辑:HenrikRock 更新时间:2/25/2021 访问量:43510
包含大于特定值的 (1) ALL 和 (2) ANY 列的子集行
subset rows with (1) ALL and (2) ANY columns larger than a specific value
问:
我有一个带有 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
如何提取所有值大于某个值(例如 10)的行,该值应返回:
# id v1 v2 # 2 2 15 32 # 4 4 12 17
如何提取 ANY(至少一个)值大于 10 的行:
# id v1 v2 # 2 2 15 32 # 4 4 12 17 # 5 5 7 11
答:
这可以使用边距 1 来完成,它将对每一行应用一个函数。检查给定行的函数是apply
function(row) {all(row > 10)}
因此,提取行本身的方法是
df[apply(df, 1, function(row) {all(row > 10)}),]
评论
all(row[-1] > 10)
id
df[-1]
分别查看函数和问题的第一部分和第二部分。该函数可用于在行或列上运行函数。(是行,是列等)。注意:在进行比较时,我使用 on 忽略该变量。all()
any()
apply()
MARGIN = 1
MARGIN = 2
apply()
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 > 10
apply()
all()
TRUE
TRUE
FALSE
any()
TRUE
TRUE
FALSE
FALSE
然后,我使用调用产生的逻辑向量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
一种选择是逐行循环(例如,使用 ) 并使用 或 ,如其他两个答案中所建议的那样。但是,对于大型数据帧,这可能效率低下。apply
any
all
矢量化方法是用于确定每行中与您的条件匹配的值数,并基于该值进行筛选。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
等效如下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
评论