比较两个data.frames以查找data.frame 1中不存在于data.frame 2中的行

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了比较两个data.frames以查找data.frame 1中不存在于data.frame 2中的行相关的知识,希望对你有一定的参考价值。

我有以下2个data.frames:

a1 <- data.frame(a = 1:5, b=letters[1:5])
a2 <- data.frame(a = 1:3, b=letters[1:3])

我想找到a1没有的行a1。

这种类型的操作是否有内置功能?

(p.s:我确实为它编写了一个解决方案,如果有人已经制作了更精心设计的代码,我感到很好奇)

这是我的解决方案:

a1 <- data.frame(a = 1:5, b=letters[1:5])
a2 <- data.frame(a = 1:3, b=letters[1:3])

rows.in.a1.that.are.not.in.a2  <- function(a1,a2)
{
    a1.vec <- apply(a1, 1, paste, collapse = "")
    a2.vec <- apply(a2, 1, paste, collapse = "")
    a1.without.a2.rows <- a1[!a1.vec %in% a2.vec,]
    return(a1.without.a2.rows)
}
rows.in.a1.that.are.not.in.a2(a1,a2)
答案

这不会直接回答您的问题,但它会为您提供共同的元素。这可以通过Paul Murrell的包compare来完成:

library(compare)
a1 <- data.frame(a = 1:5, b = letters[1:5])
a2 <- data.frame(a = 1:3, b = letters[1:3])
comparison <- compare(a1,a2,allowAll=TRUE)
comparison$tM
#  a b
#1 1 a
#2 2 b
#3 3 c

函数compare在允许哪种比较方面为您提供了很大的灵活性(例如,改变每个向量的元素顺序,改变变量的顺序和名称,缩短变量,改变字符串的大小写)。由此,您应该能够找出其中一个或哪个缺失的东西。例如(这不是很优雅):

difference <-
   data.frame(lapply(1:ncol(a1),function(i)setdiff(a1[,i],comparison$tM[,i])))
colnames(difference) <- colnames(a1)
difference
#  a b
#1 4 d
#2 5 e
另一答案

也许它太简单了,但我使用了这个解决方案,当我有一个可以用来比较数据集的主键时,我发现它非常有用。希望它可以提供帮助。

a1 <- data.frame(a = 1:5, b = letters[1:5])
a2 <- data.frame(a = 1:3, b = letters[1:3])
different.names <- (!a1$a %in% a2$a)
not.in.a2 <- a1[different.names,]
另一答案

另一种基于plyr中match_df的解决方案。这是plyr的match_df:

match_df <- function (x, y, on = NULL) 
{
    if (is.null(on)) {
        on <- intersect(names(x), names(y))
        message("Matching on: ", paste(on, collapse = ", "))
    }
    keys <- join.keys(x, y, on)
    x[keys$x %in% keys$y, , drop = FALSE]
}

我们可以修改它来否定:

library(plyr)
negate_match_df <- function (x, y, on = NULL) 
{
    if (is.null(on)) {
        on <- intersect(names(x), names(y))
        message("Matching on: ", paste(on, collapse = ", "))
    }
    keys <- join.keys(x, y, on)
    x[!(keys$x %in% keys$y), , drop = FALSE]
}

然后:

diff <- negate_match_df(a1,a2)
另一答案

使用subset

missing<-subset(a1, !(a %in% a2$a))
另一答案

SQLDF提供了一个很好的解决方案

a1 <- data.frame(a = 1:5, b=letters[1:5])
a2 <- data.frame(a = 1:3, b=letters[1:3])

require(sqldf)

a1NotIna2 <- sqldf('SELECT * FROM a1 EXCEPT SELECT * FROM a2')

以及两个数据框中的行:

a1Ina2 <- sqldf('SELECT * FROM a1 INTERSECT SELECT * FROM a2')

dplyr的新版本有一个函数anti_join,正是为了这些类型的比较

require(dplyr) 
anti_join(a1,a2)

semi_join过滤a1中的行也在a2

semi_join(a1,a2)
另一答案

在dplyr中:

setdiff(a1,a2)

基本上,setdiff(bigFrame, smallFrame)会在第一张表中为您提供额外的记录。

在SQLverse中,这称为a

Left Excluding Join Venn Diagram

有关所有连接选项和设置主题的详细描述,这是我见过的最好的摘要之一:http://www.vertabelo.com/blog/technical-articles/sql-joins

但回到这个问题 - 这是使用OP数据时setdiff()代码的结果:

> a1
  a b
1 1 a
2 2 b
3 3 c
4 4 d
5 5 e

> a2
  a b
1 1 a
2 2 b
3 3 c

> setdiff(a1,a2)
  a b
1 4 d
2 5 e

或者甚至anti_join(a1,a2)会得到相同的结果。 欲了解更多信息:https://www.rstudio.com/wp-content/uploads/2015/02/data-wrangling-cheatsheet.pdf

另一答案

对于这个特定的目的来说肯定没有效率,但在这些情况下我经常做的是在每个data.frame中插入指示符变量然后合并:

a1$included_a1 <- TRUE
a2$included_a2 <- TRUE
res <- merge(a1, a2, all=TRUE)

included_a1中缺少的值将记录a1中缺少哪些行。类似于a2。

您的解决方案的一个问题是列顺序必须匹配。另一个问题是很容易想象当行实际上不同时将行编码为相同的情况。使用合并的好处是,您可以免费获得良好解决方案所需的所有错误检查。

另一答案

我写了一个包(https://github.com/alexsanjoseph/compareDF),因为我有同样的问题。

  > df1 <- data.frame(a = 1:5, b=letters[1:5], row = 1:5)
  > df2 <- data.frame(a = 1:3, b=letters[1:3], row = 1:3)
  > df_compare = compare_df(df1, df2, "row")

  > df_compare$comparison_df
    row chng_type a b
  1   4         + 4 d
  2   5         + 5 e

一个更复杂的例子:

library(compareDF)
df1 = data.frame(id1 = c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710",
                         "Hornet 4 Drive", "Duster 360", "Merc 240D"),
                 id2 = c("Maz", "Maz", "Dat", "Hor", "Dus", "Mer"),
                 hp = c(110, 110, 181, 110, 245, 62),
                 cyl = c(6, 6, 4, 6, 8, 4),
                 qsec = c(16.46, 17.02, 33.00, 19.44, 15.84, 20.00))

df2 = data.frame(id1 = c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710",
                         "Hornet 4 Drive", " Hornet Sportabout", "Valiant"),
                 id2 = c("Maz", "Maz", "Dat", "Hor", "Dus", "Val"),
                 hp = c(110, 110, 93, 110, 175, 105),
                 cyl = c(6, 6, 4, 6, 8, 6),
                 qsec = c(16.46, 17.02, 18.61, 19.44, 17.02, 20.22))

> df_compare$comparison_df
    grp chng_type                id1 id2  hp cyl  qsec
  1   1         -  Hornet Sportabout Dus 175   8 17.02
  2   2         +         Datsun 710 Dat 181   4 33.00
  3   2         -         Datsun 710 Dat  93   4 18.61
  4   3         +         Duster 360 Dus 245   8 15.84
  5   7         +          Merc 240D Mer  62   4 20.00
  6   8         -            Valiant Val 105   6 20.22

该软件包还有一个html_output命令,用于快速检查

df_compare $ html_output enter image description here

另一答案

你可以使用daff package(使用daff.js library包装V8 package):

library(daff)

diff_data(data_ref = a2,
          data = a1)

产生以下差异对象:

Daff Comparison: ‘a2’ vs. ‘a1’ 
  First 6 and last 6 patch lines:
   @@   a   b
1 ... ... ...
2       3   c
3 +++   4   d
4 +++   5   e
5 ... ... ...
6 ... ... ...
7       3   c
8 +++   4   d
9 +++   5   e

差异格式在Coopy highlighter diff format for tables中描述,应该是非常明显的。第一列+++@@的线是a1中的新线并且不存在于a2中。

差异对象可用于patch_data(),使用write_diff()存储差异以用于文档目的或使用render_diff()可视化差异:

render_diff(
    diff_data(data_ref = a2,
              data = a1)
)

生成一个整洁的HTML输出:

enter image description here

另一答案

使用diffobj包:

library(diffobj)

diffPrint(a1, a2)
diffObj(a1, a2)

保存和加载data.frames [重复]

R语言ggplot2可视化将两个dataframe可视化的结果组合在一起实战:combining two plots from different data.frames

R - 子集列表data.frames由矢量值

ggplot 在不同的 data.frames 中带有 x 和 y 变量,带有 For-Loop

将第N行的NAs插入到data.frames列表中,从列表中插入N行。

合并大量data.frames [重复]