【问题标题】:R selecting all rows from a data frame that don't appear in anotherR从数据框中选择未出现在另一个数据框中的所有行
【发布时间】:2013-06-29 22:59:39
【问题描述】:

我正在尝试解决一个棘手的 R 问题,我无法通过谷歌搜索关键字来解决。具体来说,我正在尝试获取一个数据帧的子集,其值不会出现在另一个数据帧中。这是一个例子:

> test
      number    fruit     ID1  ID2 
item1 "number1" "apples"  "22" "33"
item2 "number2" "oranges" "13" "33"
item3 "number3" "peaches" "44" "25"
item4 "number4" "apples"  "12" "13"
> test2
      number    fruit     ID1   ID2 
item1 "number1" "papayas" "22"  "33"
item2 "number2" "oranges" "13"  "33"
item3 "number3" "peaches" "441" "25"
item4 "number4" "apples"  "123" "13"
item5 "number3" "peaches" "44"  "25"
item6 "number4" "apples"  "12"  "13"
item7 "number1" "apples"  "22"  "33"

我有两个数据框,test 和 test2,目标是选择 test2 中未出现在 test 中的所有整行,即使其中一些值可能相同。

我想要的输出如下:

item1 "number1" "papayas" "22"  "33"
item2 "number3" "peaches" "441" "25"
item3 "number4" "apples"  "123" "13"

可能有任意数量的行或列,但在我的具体情况下,一个数据框是另一个数据框的直接子集。

我已经广泛使用了 R 的子集()、merge() 和 which() 函数,但不知道如何组合使用这些函数,如果可能的话,得到我想要的。

edit:这是我用来生成这两个表的 R 代码。

test <- data.frame(c("number1", "apples", 22, 33), c("number2", "oranges", 13, 33),
    c("number3", "peaches", 44, 25), c("number4", "apples", 12, 13))

test <- t(test)
rownames(test) = c("item1", "item2", "item3", "item4")
colnames(test) = c("number", "fruit", "ID1", "ID2")

test2 <- data.frame(data.frame(c("number1", "papayas", 22, 33), c("number2", "oranges", 13, 33),
    c("number3", "peaches", 441, 25), c("number4", "apples", 123, 13),c("number3", "peaches", 44, 25), c("number4", "apples", 12, 13)  ))

test2 <- t(test2)
rownames(test2) = c("item1", "item2", "item3", "item4", "item5", "item6")
colnames(test2) = c("number", "fruit", "ID1", "ID2")

提前致谢!

【问题讨论】:

  • 你没有数据框,你有矩阵。不要在数据框上使用t。幸运的是,merge 足够聪明,可以将您的矩阵重新转换为数据框。对我来说不幸的是,将id(现在属于factor)转换为数字还不够聪明......
  • 感谢您的尝试,洪!我的真实数据集属于 data.frame 类,不幸的是,您的代码也不适用于该数据集 =\。对象匹配出来是一个 NULL 对象
  • 所需输出中的行名与test2 不匹配。这是一个错误吗?
  • 哦,是的。请忽略那些行名,这是一个假设的输出!
  • 我希望有办法从plyr 中否定match_df

标签: r dataframe subset


【解决方案1】:

这是另一种方式:

x <- rbind(test2, test)
x[! duplicated(x, fromLast=TRUE) & seq(nrow(x)) <= nrow(test2), ]
#        number   fruit ID1 ID2
# item1 number1 papayas  22  33
# item3 number3 peaches 441  25
# item4 number4  apples 123  13

编辑:修改为保留行名。

【讨论】:

  • 我正在尝试用我的真实数据编写代码,它似乎运行良好。我遇到的一个小问题是它会删除所有重复项,这可能并不理想(因为某些记录实际上应该有重复项,例如如果一位客户购买了两个相同的产品)。不过,这对于我现在拥有的数据来说已经足够了,谢谢!
  • 这是一个很好的解决方案,可以解决我一直称之为子集化中的“双重否定”问题。我试图做一个一步子集来消除 DF 中的值,该值在两个列上具有我不想要的值的组合;例如,“subset(df, HIYA != "alpha" & BYA != "beta") -- 我想要的是除了 HIYA = alpha 和 BYA = beta 的情况之外的所有内容。这就解决了!
  • 看起来是一个很好的答案,但老实说我看不懂代码。为什么我们需要一个序列?
  • !dulpicated() 返回一个长度为 x 的逻辑向量,在不重复的情况下为 TRUE。 fromLast 将 TRUE 推到向量的末尾(因为它们现在是“第一次”出现)。 seq()&lt;= 创建一个带有 length(test2) TRUEs 后跟 'length(test)` FALSEs 的向量,最后过滤掉所有虚假的 TRUEs。等效构造为:x &lt;- rbind(test, test2)x[! duplicated(x) &amp; seq(nrow(x)) &gt; nrow(test2), ]
【解决方案2】:

有两种方法可以解决这个问题,使用 data.table 和 sqldf

library(data.table)
test<- fread('
item number fruit ID1 ID2 
item1 "number1" "apples"  "22" "33"
item2 "number2" "oranges" "13" "33"
item3 "number3" "peaches" "44" "25"
item4 "number4" "apples"  "12" "13"
')
test2<- fread('
item number fruit ID1 ID2 
item1 "number1" "papayas" "22"  "33"
item2 "number2" "oranges" "13"  "33"
item3 "number3" "peaches" "441" "25"
item4 "number4" "apples"  "123" "13"
item5 "number3" "peaches" "44"  "25"
item6 "number4" "apples"  "12"  "13"
item7 "number1" "apples"  "22"  "33"
')

data.table 方法,这使您可以选择要比较的列

setkey(test,item,number,fruit,ID1,ID2)
setkey(test2,item,number,fruit,ID1,ID2)
test[!test2]
item  number   fruit ID1 ID2
1: item1 number1  apples  22  33
2: item3 number3 peaches  44  25
3: item4 number4  apples  12  13

Sql方法

sqldf('select * from test except select * from test2')
item  number   fruit ID1 ID2
1: item1 number1  apples  22  33
2: item3 number3 peaches  44  25
3: item4 number4  apples  12  13

【讨论】:

    【解决方案3】:

    以下内容应该可以帮助您:

    rows <- unique(unlist(mapply(function(x, y) 
              sapply(setdiff(x, y), function(d) which(x==d)), test2, test1)))
    test2[rows, ]
    

    这里发生的事情是:

    • mapply 用于在两个数据集之间进行逐列比较。
    • 它使用setdiff 来查找在前者但不属于后者的任何项目
    • which 标识前者的哪一行不存在。
    • unique(unlist(....)) 抓取所有唯一行

    • 然后我们将其用作对前者的过滤器,即test2

    结果:

           number   fruit ID1 ID2
    item1 number1 papayas  22  33
    item3 number3 peaches 441  25
    item4 number4  apples 123  13
    

    编辑:

    确保您的testtest2data.frames 而不是matrices,因为mapply 会遍历矩阵的每个元素,但会遍历每个 data.frame

    test  <- as.data.frame(test,  stringsAsFactors=FALSE)
    test2 <- as.data.frame(test2, stringsAsFactors=FALSE)
    

    【讨论】:

    • 不幸的是,这只给出了一行作为输出,而且不是重复的!我编辑了原始帖子以包含我用来生成表格的代码,也许你可以自己看看
    • 啊……你说你有data.frames,而实际上你有matrices。请看编辑。转换为 data.frame 一切都很好;)
    • 一切都不是很好......还没有!从结果可以看出,它们实际上是不正确的。 item2 在 'test' 和 'test2' 中都重复,并且 test2 中的两个唯一行不会显示在结果中。
    • 我的错误,mapply 函数中有错误。但是,数据仍然需要是 data.frames 字符串不能是因素。
    【解决方案4】:

    使用包dplyr,也可以使用anti_join。

    missing.species &lt;- anti_join(test2, test, by = NULL)

    它将返回在 test 中没有匹配的 test2 行。通过显式加入的变量。如果为 NULL,该函数将使用 test 和 test2 中的所有变量。

    【讨论】:

      【解决方案5】:

      在test2中新建一个row-ID列,合并数据框,并选择那些ID不在合并结果中的行。

      test2 <- cbind(test2, id=seq_len(nrow(test2)))
      
      matches <- merge(test1, test2)$id
      
      test2 <- test2[-matches, ]
      

      【讨论】:

      • 这给出了一个错误:警告消息:在 Ops.factor(matches) 中:-对于我在 OP 中编辑的代码没有意义
      【解决方案6】:

      这是另一种方法,但我不确定它的扩展性如何。

      test2[!apply(test2, 1, paste, collapse = "") %in% 
              apply(test, 1, paste, collapse = ""), ]
      #       number    fruit     ID1   ID2 
      # item1 "number1" "papayas" "22"  "33"
      # item3 "number3" "peaches" "441" "25"
      # item4 "number4" "apples"  "123" "13"
      

      不会删除所有重复项。例如,比较 test2 是否有重复项:

      test2 <- rbind(test2, test2[1:3, ])
      
      ## Matthew's answer: Duplicates dropped
      x <- rbind(test2, test)
      x[! duplicated(x, fromLast=TRUE) & seq(nrow(x)) <= nrow(test2), ]
      #       number    fruit     ID1   ID2 
      # item4 "number4" "apples"  "123" "13"
      # item1 "number1" "papayas" "22"  "33"
      # item3 "number3" "peaches" "441" "25"
      
      ## This one: Duplicates retained
      test2[!apply(test2, 1, paste, collapse = "") %in%
        apply(test, 1, paste, collapse = ""), ]
      #       number    fruit     ID1   ID2 
      # item1 "number1" "papayas" "22"  "33"
      # item3 "number3" "peaches" "441" "25"
      # item4 "number4" "apples"  "123" "13"
      # item1 "number1" "papayas" "22"  "33"
      # item3 "number3" "peaches" "441" "25"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-06
        • 2023-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-07
        • 2023-04-02
        相关资源
        最近更新 更多