【问题标题】: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%,但这似乎不存在。 有什么想法吗?

【问题讨论】:

    标签: r dataframe subset


    【解决方案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; 运算符由逗号隐含。

            【讨论】:

              猜你喜欢
              • 2014-08-03
              • 2020-08-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-06-14
              • 2017-11-26
              • 1970-01-01
              相关资源
              最近更新 更多