Сравните два data.frames, чтобы найти строки в data.frame 1, которых нет в data.frame 2

Для этого вам нужно использовать отражение:

typeof(Session).GetMethod("Linq").MakeGenericMethod(typeOne).Invoke(null, null);

(предполагая, что Linq<T>() является статическим методом для типа Session)

Если Session на самом деле является объектом , вам нужно знать, где фактически объявлен метод Linq, и передать в Session в качестве аргумента:

typeof(DeclaringType).GetMethod("Linq").MakeGenericMethod(typeOne)
     .Invoke(null, new object[] {Session});
140
задан Tal Galili 3 July 2010 в 12:04
поделиться

3 ответа

Это не дает прямого ответа на ваш вопрос, но дает вам общие элементы. Это можно сделать с помощью пакета Пола Мюррелла 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
85
ответ дан 23 November 2019 в 22:08
поделиться

Это, конечно, неэффективно для этой конкретной цели, но то, что я часто делаю в таких ситуациях, - это вставляю индикаторные переменные в каждый data.frame, а затем объединяю:

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

отсутствующие значения в include_a1 будут обратите внимание, какие строки отсутствуют в a1. аналогично для a2.

Одна из проблем с вашим решением состоит в том, что порядок столбцов должен совпадать. Другая проблема заключается в том, что легко представить себе ситуации, когда строки имеют одинаковый код, хотя на самом деле они разные. Преимущество использования слияния заключается в том, что вы бесплатно получаете всю проверку ошибок, необходимую для хорошего решения.

39
ответ дан 23 November 2019 в 22:08
поделиться

Я адаптировал функцию 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)
}
8
ответ дан 23 November 2019 в 22:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: