通过要删除的行的多个逻辑条件子集数据帧
Posted
技术标签:
【中文标题】通过要删除的行的多个逻辑条件子集数据帧【英文标题】:Subset dataframe by multiple logical conditions of rows to remove 【发布时间】:2011-09-08 19:25:15 【问题描述】:我想通过指定将哪些行不 (!
) 保留在新数据框中来对数据框进行子集化(过滤)。这是一个简化的示例数据框:
data
v1 v2 v3 v4
a v d c
a v d d
b n p g
b d d h
c k d c
c r p g
d v d x
d v d c
e v d b
e v d c
例如,如果列 v1 的一行有“b”、“d”或“e”,我想去掉那一行观察结果,生成以下数据框:
v1 v2 v3 v4
a v d c
a v d d
c k d c
c r p g
我一次成功地根据一个条件进行子集化。例如,这里我删除了 v1 包含“b”的行:
sub.data <- data[data[ , 1] != "b", ]
但是,我有很多很多这样的条件,所以一次做一个是不可取的。我在以下方面没有成功:
sub.data <- data[data[ , 1] != c("b", "d", "e")
或
sub.data <- subset(data, data[ , 1] != c("b", "d", "e"))
我也尝试了一些其他的东西,比如!%in%
,但这似乎不存在。
有什么想法吗?
【问题讨论】:
【参考方案1】:试试这个
subset(data, !(v1 %in% c("b","d","e")))
【讨论】:
很好很简单,谢谢。我不确定我更喜欢哪种解决方案,这个解决方案还是 Andrie 提供的解决方案。它们既简单又有效。这三种解决方案都对我有用,我以前从未使用过which()
。所以,很高兴被介绍到该功能。
如果它可以帮助您决定是使用subset
还是[
,请查看?subset
帮助中的警告:"这是旨在交互使用的便利函数。对于编程,最好使用标准子集函数,例如 [,特别是参数子集的非标准评估可能会产生意想不到的后果。”
@Andrie 感谢您的澄清。【参考方案2】:
!
应该在语句的外面:
data[!(data$v1 %in% c("b", "d", "e")), ]
v1 v2 v3 v4
1 a v d c
2 a v d d
5 c k d c
6 c r p g
【讨论】:
【参考方案3】:您还可以通过包含 &
来分隔语句来将事物分解为单独的逻辑语句来实现此目的。
subset(my.df, my.df$v1 != "b" & my.df$v1 != "d" & my.df$v1 != "e")
这并不优雅,需要更多代码,但对于新的 R 用户来说可能更具可读性。正如上面评论中所指出的,subset
是一个“便利”功能,最适合在交互工作时使用。
【讨论】:
不应该是|
而不是&
吗?
@BenBolker 如果您更改为|
,您将获得与输入相同的数据。
@Frank 你能解释一下&
与!=
配对的逻辑吗?像 Ben 一样,似乎应该使用 |
,但你说得对,它不应该使用。我对以这种方式对多个列进行子集化感到特别困惑。例如,使用上面 Herman 的示例数据,要从 v1 中删除所有“b”案例,从 v2 中删除所有“n”,我认为my.df[my.df$v1 != "b" & my.df$v2 != "n",]
只会删除同时满足这两个标准的案例(即只有第 3 行),而不是这些标准中的任何一个(即第 3 行和第 4 行)。事实上,使用|
和!=
可以达到我期望&
的效果,但我不明白为什么。
如果有|
,任何条件中的单个TRUE
结果将导致整个语句计算为TRUE
。所有条件都必须计算为FALSE
,语句才能计算为FALSE
。对于&
,单个FALSE
条件将使整个语句计算为FALSE
。如果要使用or,可以使用exclusive or:xor
,像这样:subset(my.df, xor(xor(my.df$v1 != "b", my.df$v1 != "d"), my.df$v1 != "e"))
。【参考方案4】:
这个答案更多的是解释为什么,而不是如何。 R 中的 '=='
运算符以与 '+'
运算符相同的方式进行矢量化。它将左侧任何元素的元素与右侧任何元素的元素匹配,每个元素。例如:
> 1:3 == 1:3
[1] TRUE TRUE TRUE
这里第一个测试是1==1
,它是TRUE,第二个是2==2
,第三个是3==3
。请注意,这会在第一个和第二个元素中返回 FALSE,因为顺序错误:
> 3:1 == 1:3
[1] FALSE TRUE FALSE
现在,如果一个对象比另一个对象小,那么较小的对象会尽可能多地重复以匹配较大的对象。如果较大对象的大小不是较小对象大小的乘积,则会收到警告,指出并非所有元素都重复。例如:
> 1:2 == 1:3
[1] TRUE TRUE FALSE
Warning message:
In 1:2 == 1:3 :
longer object length is not a multiple of shorter object length
这里第一个匹配是1==1
,然后是2==2
,最后是1==3
(FALSE),因为左侧更小。如果其中一侧只有一个元素,则重复:
> 1:3 == 1
[1] TRUE FALSE FALSE
测试元素是否在向量中的正确运算符确实是'%in%'
,它仅向量化到左元素(对于左向量中的每个元素,它会测试它是否是右元素中任何对象的一部分)。
或者,您可以使用'&'
组合两个逻辑语句。 '&'
接受两个元素并逐元素检查两者是否为真:
> 1:3 == 1 & 1:3 != 2
[1] TRUE FALSE FALSE
【讨论】:
【参考方案5】:data <- data[-which(data[,1] %in% c("b","d","e")),]
【讨论】:
-which
是邪恶的,如果要匹配的向量中没有任何值在源向量中,则会产生意想不到的结果。【参考方案6】:
my.df <- read.table(textConnection("
v1 v2 v3 v4
a v d c
a v d d
b n p g
b d d h
c k d c
c r p g
d v d x
d v d c
e v d b
e v d c"), header = TRUE)
my.df[which(my.df$v1 != "b" & my.df$v1 != "d" & my.df$v1 != "e" ), ]
v1 v2 v3 v4
1 a v d c
2 a v d d
5 c k d c
6 c r p g
【讨论】:
【参考方案7】:sub.data<-data[ data[,1] != "b" & data[,1] != "d" & data[,1] != "e" , ]
更大但易于理解(我猜)并且可以与多个列一起使用,即使是!is.na( data[,1])
。
【讨论】:
【参考方案8】:还有
library(dplyr)
data %>% filter(!v1 %in% c("b", "d", "e"))
或
data %>% filter(v1 != "b" & v1 != "d" & v1 != "e")
或
data %>% filter(v1 != "b", v1 != "d", v1 != "e")
由于&
运算符由逗号隐含。
【讨论】:
以上是关于通过要删除的行的多个逻辑条件子集数据帧的主要内容,如果未能解决你的问题,请参考以下文章