data.frame 2에 존재하지 않는 data.frame 1의 행을 찾으려면 두 개의 data.frame을 비교하십시오.
다음과 같은 2 개의 data.frame이 있습니다.
a1 <- data.frame(a = 1:5, b=letters[1:5])
a2 <- data.frame(a = 1:3, b=letters[1:3])
a1에 a2가없는 행을 찾고 싶습니다.
이 유형의 작업에 내장 된 기능이 있습니까?
(ps : 나는 그것을 위해 해결책을 썼다. 누군가 이미 더 만들어진 코드를 만들면 궁금하다.)
내 해결책은 다음과 같습니다.
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
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에서는 이것을
모든 조인 옵션 및 주제 설정에 대한 자세한 설명을 보려면, 지금까지 함께 살펴본 최고의 요약 중 하나입니다. http://www.vertabelo.com/blog/technical-articles/sql-joins
그러나이 질문으로 돌아 가면 setdiff()
OP의 데이터를 사용할 때 의 코드 결과는 다음과 같습니다.
> 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 명령도 있습니다
당신이 사용할 수있는 daff
패키지 (감쌈 daff.js
도서관 은 Using V8
패키지 ) :
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
diff 형식은 표에 대한 Coopy 형광펜 diff 형식으로 설명되어 있으며 매우 자명해야합니다. +++
첫 번째 열에 있는 줄 @@
은에 새롭고 a1
존재하지 않는 줄입니다 a2
.
차이점 개체는 다음을 사용하여 patch_data()
문서 목적으로 차이점을 저장 write_diff()
하거나 다음을 사용하여 차이점render_diff()
을 시각화하는 데 사용할 수 있습니다 .
render_diff(
diff_data(data_ref = a2,
data = a1)
)
깔끔한 HTML 출력을 생성합니다.
diffobj
패키지 사용 :
library(diffobj)
diffPrint(a1, a2)
diffObj(a1, a2)
이 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)
}
Your example data does not have any duplicates, but your solution handle them automatically. This means that potentially some of the answers won't match to results of your function in case of duplicates.
Here is my solution which address duplicates the same way as yours. It also scales great!
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
It needs data.table 1.9.8+
Maybe it is too simplistic, but I used this solution and I find it very useful when I have a primary key that I can use to compare data sets. Hope it can help.
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,]
Yet another solution based on match_df in plyr. Here's plyr's 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]
}
We can modify it to negate:
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]
}
Then:
diff <- negate_match_df(a1,a2)
Using subset
:
missing<-subset(a1, !(a %in% a2$a))
'Programing' 카테고리의 다른 글
“varargs 매개 변수에 대해 일반 T 배열이 만들어집니다”컴파일러 경고를 해결할 수 있습니까? (0) | 2020.06.13 |
---|---|
성공 및 오류 대신 새 jQuery AJAX 코드에 .done () 및 .fail ()을 사용해야합니까 (0) | 2020.06.13 |
jQuery는 div 태그 안에 이미지를 추가합니다. (0) | 2020.06.12 |
정적 라이브러리의 Objective-C 범주 (0) | 2020.06.12 |
Ajax post ASP.NET MVC에 antiforgerytoken 포함 (0) | 2020.06.12 |