Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
比较两个data.frame以查找data.frame 1中不在data.frame 2中的行_R_Merge_Compare_Rows_Dataframe - Fatal编程技术网

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

比较两个data.frame以查找data.frame 1中不在data.frame 2中的行,r,merge,compare,rows,dataframe,R,Merge,Compare,Rows,Dataframe,我有以下2个data.frames: a1 <- data.frame(a = 1:5, b=letters[1:5]) a2 <- data.frame(a = 1:3, b=letters[1:3]) a1对于这个特定的目的来说,它当然不是很有效,但在这些情况下,我经常做的是在每个data.frame中插入指示符变量,然后合并: a1$included_a1 <- TRUE a2$included_a2 <- TRUE res <- merge(a1, a2,

我有以下2个data.frames:

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

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

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

a1$included_a1这并不能直接回答您的问题,但它将为您提供共同的元素。这可以通过Paul Murrell的软件包实现:


我调整了
merge
函数以获得此功能。在较大的数据帧上,它使用的内存少于完整合并解决方案。我可以玩关键列的名称

另一个解决方案是使用库
prob

#  Derived from src/library/base/R/merge.R
#  Part of the R package, http://www.R-project.org
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  A copy of the GNU General Public License is available at
#  http://www.r-project.org/Licenses/

XinY <-
    function(x, y, by = intersect(names(x), names(y)), by.x = by, by.y = by,
             notin = FALSE, incomparables = NULL,
             ...)
{
    fix.by <- function(by, df)
    {
        ## fix up 'by' to be a valid set of cols by number: 0 is row.names
        if(is.null(by)) by <- numeric(0L)
        by <- as.vector(by)
        nc <- ncol(df)
        if(is.character(by))
            by <- match(by, c("row.names", names(df))) - 1L
        else if(is.numeric(by)) {
            if(any(by < 0L) || any(by > nc))
                stop("'by' must match numbers of columns")
        } else if(is.logical(by)) {
            if(length(by) != nc) stop("'by' must match number of columns")
            by <- seq_along(by)[by]
        } else stop("'by' must specify column(s) as numbers, names or logical")
        if(any(is.na(by))) stop("'by' must specify valid column(s)")
        unique(by)
    }

    nx <- nrow(x <- as.data.frame(x)); ny <- nrow(y <- as.data.frame(y))
    by.x <- fix.by(by.x, x)
    by.y <- fix.by(by.y, y)
    if((l.b <- length(by.x)) != length(by.y))
        stop("'by.x' and 'by.y' specify different numbers of columns")
    if(l.b == 0L) {
        ## was: stop("no columns to match on")
        ## returns x
        x
    }
    else {
        if(any(by.x == 0L)) {
            x <- cbind(Row.names = I(row.names(x)), x)
            by.x <- by.x + 1L
        }
        if(any(by.y == 0L)) {
            y <- cbind(Row.names = I(row.names(y)), y)
            by.y <- by.y + 1L
        }
        ## create keys from 'by' columns:
        if(l.b == 1L) {                  # (be faster)
            bx <- x[, by.x]; if(is.factor(bx)) bx <- as.character(bx)
            by <- y[, by.y]; if(is.factor(by)) by <- as.character(by)
        } else {
            ## Do these together for consistency in as.character.
            ## Use same set of names.
            bx <- x[, by.x, drop=FALSE]; by <- y[, by.y, drop=FALSE]
            names(bx) <- names(by) <- paste("V", seq_len(ncol(bx)), sep="")
            bz <- do.call("paste", c(rbind(bx, by), sep = "\r"))
            bx <- bz[seq_len(nx)]
            by <- bz[nx + seq_len(ny)]
        }
        comm <- match(bx, by, 0L)
        if (notin) {
            res <- x[comm == 0,]
        } else {
            res <- x[comm > 0,]
        }
    }
    ## avoid a copy
    ## row.names(res) <- NULL
    attr(res, "row.names") <- .set_row_names(nrow(res))
    res
}


XnotinY <-
    function(x, y, by = intersect(names(x), names(y)), by.x = by, by.y = by,
             notin = TRUE, incomparables = NULL,
             ...)
{
    XinY(x,y,by,by.x,by.y,notin,incomparables)
}
#派生自src/library/base/R/merge.R
#R包的一部分,http://www.R-project.org
#
#这个程序是自由软件;您可以重新分发和/或修改它
#它是根据GNU通用公共许可证的条款发布的
自由软件基金会;许可证的第2版,或
#(由您选择)任何更高版本。
#
#这个节目的发布是希望它会有用,
#但无任何保证;甚至没有任何关于
#适销性或适合某一特定目的。见
#有关更多详细信息,请参阅GNU通用公共许可证。
#
#GNU通用公共许可证的副本可在
#  http://www.r-project.org/Licenses/

Xyni
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')
semi_join
以过滤
a1
中也位于
a2

semi_join(a1,a2)
我写了一个包(),因为我有同样的问题

  > 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
该包还有一个用于快速检查的html_输出命令

df_比较$html_输出


另一个基于plyr中match_df的解决方案。 以下是plyr的比赛:

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]
}

match_df您的示例数据没有任何重复项,但您的解决方案会自动处理它们。这意味着在出现重复的情况下,某些答案可能与函数的结果不匹配。
这是我的解决方案,它的地址与您的地址相同。它的规模也很大

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

library(data.table)
setDT(a1)
setDT(a2)

# no duplicates - as in example code
r <- fsetdiff(a1, a2)
all.equal(r, rows.in.a1.that.are.not.in.a2(a1,a2))
#[1] TRUE

# handling duplicates - make some duplicates
a1 <- rbind(a1, a1, a1)
a2 <- rbind(a2, a2, a2)
r <- fsetdiff(a1, a2, all = TRUE)
all.equal(r, rows.in.a1.that.are.not.in.a2(a1,a2))
#[1] TRUE


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

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,]

a1使用
diffobj
包:

library(diffobj)

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

在dplyr中:

基本上,
setdiff(bigFrame,smallFrame)
在第一个表中获取额外的记录

在SQLverse中,这称为

为了更好地描述所有连接选项和集合主题,这是我迄今为止看到的最好的总结之一:

但回到这个问题-以下是使用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)
也会得到同样的结果。
有关详细信息:

您可以使用(使用包装):

库(daff)
差异数据(数据参考=a2,
数据=a1)
生成以下差异对象:

Daff比较:“a2”与“a1”
前6条和最后6条配线:
@@a b
1.
2 3 c
3+++4 d
4+++5 e
5.
6.
7.3 c
8+++4 d
9++5 e
描述了表格格式的diff格式,应该是非常自解释的。第一列
@
中带有
++
的行是
a1
中新增的行,在
a2
中不存在

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

render_diff(
差异数据(数据参考=a2,
数据=a1)
)
生成整洁的HTML输出:


使用
子集:

missing<-subset(a1, !(a %in% a2$a))

缺失以下代码同时使用
数据。表
快速匹配
用于提高速度

library("data.table")
library("fastmatch")

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

compare_rows <- a1$a %fin% a2$a
# the %fin% function comes from the `fastmatch` package

added_rows <- a1[which(compare_rows == FALSE)]

added_rows

#    a b
# 1: 4 d
# 2: 5 e
库(“data.table”)
库(“快速匹配”)

a1非常快速的比较,以计算差异。 使用特定的列名

colname = "CreatedDate" # specify column name
index <- match(colname, names(source_df)) # get index name for column name
sel <- source_df[, index] == target_df[, index] # get differences, gives you dataframe with TRUE and FALSE values
table(sel)["FALSE"] # count of differences
table(sel)["TRUE"] # count of matches
colname=“CreatedDate”#指定列名

我发现这个函数令人困惑。我原以为它对我有用,但似乎只有当一个集合包含另一个集合的相同匹配行时,它才会像上面所示那样工作。考虑这种情况:<代码> A2…在查找缺少的值时,您创建了另一个缺少的值。。。如何查找包含的
中缺少的值-/使用is.na()和subset,或dplyr::filter感谢您在不安装新库的情况下教授一种方法!感谢
anti_-join
semi_-join
!反_-join会像sqldf一样返回null DF,但函数相同(a1、a2)和all.equal()会与此相矛盾吗?我只是想在这里补充一点,反_-join和半_-join在某些情况下不起作用。我得到的数据框是“错误:列必须是1d原子向量或列表”。也许我可以处理我的数据,让这些函数工作。Sqldf在大门外工作@AkshayGaur它应该只是一个数据格式或数据清理问题;sqldf就是sql,所有东西都经过预处理,就像nromal DB一样,这样我们就可以在数据上运行sql了。这和OP已经尝试过的有什么不同?您使用了与Tal完全相同的代码来比较单个列而不是整行(这是必需的),因为OP要求
a1
中不在
a2
中的项,您不想使用类似
semi_-join(a1,a2,by=c('a','b'))的东西吗
?在“Rickard”的回答中,我看到有人建议
semi_join
。当然!另一个伟大的选择也是;特别是当您的数据帧只有一个连接键和不同的列名时。setdiff来自lubridate::setdiff,而不是来自library(dply)
diff <- negate_match_df(a1,a2)
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)
}

library(data.table)
setDT(a1)
setDT(a2)

# no duplicates - as in example code
r <- fsetdiff(a1, a2)
all.equal(r, rows.in.a1.that.are.not.in.a2(a1,a2))
#[1] TRUE

# handling duplicates - make some duplicates
a1 <- rbind(a1, a1, a1)
a2 <- rbind(a2, a2, a2)
r <- fsetdiff(a1, a2, all = TRUE)
all.equal(r, rows.in.a1.that.are.not.in.a2(a1,a2))
#[1] TRUE
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,]
library(diffobj)

diffPrint(a1, a2)
diffObj(a1, a2)
setdiff(a1,a2)
> 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
missing<-subset(a1, !(a %in% a2$a))
library("data.table")
library("fastmatch")

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

compare_rows <- a1$a %fin% a2$a
# the %fin% function comes from the `fastmatch` package

added_rows <- a1[which(compare_rows == FALSE)]

added_rows

#    a b
# 1: 4 d
# 2: 5 e
colname = "CreatedDate" # specify column name
index <- match(colname, names(source_df)) # get index name for column name
sel <- source_df[, index] == target_df[, index] # get differences, gives you dataframe with TRUE and FALSE values
table(sel)["FALSE"] # count of differences
table(sel)["TRUE"] # count of matches
sel <- source_df[, ] == target_df[, ] # gives you dataframe with TRUE and FALSE values
table(sel)["FALSE"] # count of differences
table(sel)["TRUE"] # count of matches