通过要删除的行的多个逻辑条件子集数据帧

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】:

您还可以通过包含 &amp; 来分隔语句来将事物分解为单独的逻辑语句来实现此目的。

subset(my.df, my.df$v1 != "b" & my.df$v1 != "d" & my.df$v1 != "e")

这并不优雅,需要更多代码,但对于新的 R 用户来说可能更具可读性。正如上面评论中所指出的,subset 是一个“便利”功能,最适合在交互工作时使用。

【讨论】:

不应该是| 而不是&amp; 吗? @BenBolker 如果您更改为|,您将获得与输入相同的数据。 @Frank 你能解释一下&amp;!= 配对的逻辑吗?像 Ben 一样,似乎应该使用 |,但你说得对,它不应该使用。我对以这种方式对多个列进行子集化感到特别困惑。例如,使用上面 Herman 的示例数据,要从 v1 中删除所有“b”案例,从 v2 中删除所有“n”,我认为my.df[my.df$v1 != "b" &amp; my.df$v2 != "n",] 只会删除同时满足这两个标准的案例(即只有第 3 行),而不是这些标准中的任何一个(即第 3 行和第 4 行)。事实上,使用|!= 可以达到我期望&amp; 的效果,但我不明白为什么。 如果有|,任何条件中的单个TRUE 结果将导致整个语句计算为TRUE。所有条件都必须计算为FALSE,语句才能计算为FALSE。对于&amp;,单个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%',它仅向量化到左元素(对于左向量中的每个元素,它会测试它是否是右元素中任何对象的一部分)。

或者,您可以使用'&amp;' 组合两个逻辑语句。 '&amp;' 接受两个元素并逐元素检查两者是否为真:

> 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")

由于&amp; 运算符由逗号隐含。

【讨论】:

以上是关于通过要删除的行的多个逻辑条件子集数据帧的主要内容,如果未能解决你的问题,请参考以下文章

基于多个条件的子集数据框[重复]

获取具有特定数量的重复值的行

获取被筛选器从 spark 数据帧中删除的行的示例

基于分组数据帧中的两个条件的子集

在 df1 中删除也在 df2 中的行的可靠方法

使用复杂的条件逻辑加入 Pyspark 数据帧(可能使用地图代替)