하나의 data.frame에서 두 번째 data.frame에 없는 행을 선택합니다.
두 개의 data.frame이 있습니다.
a1 <- data.frame(a = 1:5, b=letters[1:5])
a2 <- data.frame(a = 1:3, b=letters[1:3])
저는 a1이 가지고 있는 행을 찾고 싶습니다. a2는 가지고 있지 않습니다.
이런 종류의 작업에 내장된 기능이 있습니까?
(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)
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)
인플라이어:
setdiff(a1,a2)
기본적으로,setdiff(bigFrame, smallFrame)
첫 번째 테이블의 추가 레코드를 가져옵니다.
SQL 버전에서 이것은 a라고 불립니다.
모든 가입 옵션과 설정된 주제에 대한 좋은 설명을 위해, 이것은 제가 지금까지 정리한 것 중 가장 좋은 요약 중 하나입니다: 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 에서 확인하시기 바랍니다.
이것은 당신의 질문에 직접적으로 대답하지는 않지만, 공통적인 요소들을 제공할 것입니다.이것은 Paul Murrell의 패키지로 수행할 수 있습니다.
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
이러한 특정한 목적을 위해 효율적이지는 않지만 이러한 상황에서 자주 하는 것은 각 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_df$df_output
패키지를 사용할 수 있습니다(패키지를 사용하여 라이브러리를 감싼 경우).
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 형식은 여기에 설명되어 있으며 매우 자명해야 합니다.와의 라인은+++
번째 @@
에 새로운 것들입니다.a1
하지않는에 없습니다.a2
.
차분 객체는 다음과 같은 용도로 사용할 수 있습니다.patch_data()
목사차저장이를여용하를 사용하여 합니다.write_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)
}
예제 데이터에는 중복 항목이 없지만 솔루션에서 자동으로 처리합니다.이는 중복되는 경우 일부 답변이 기능의 결과와 일치하지 않을 수 있음을 의미합니다.
여기 당신의 주소와 같은 방식으로 중복되는 제 솔루션이 있습니다.그것은 또한 매우 잘 확장됩니다!
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
데이터가 필요합니다. 표 1.9.8+
너무 단순할 수도 있지만 이 솔루션을 사용했는데 데이터 세트를 비교하는 데 사용할 수 있는 기본 키가 있을 때 매우 유용합니다.도움이 되길 바랍니다.
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,]
용사를 합니다.subset
:
missing<-subset(a1, !(a %in% a2$a))
그러나 match_df in plyr을 기반으로 하는 또 다른 솔루션.다음은 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]
}
부정하도록 수정할 수 있습니다.
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)
다음 코드는 두 가지를 모두 사용합니다.data.table
그리고.fastmatch
속도를 높이기 위해
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
언급URL : https://stackoverflow.com/questions/3171426/select-rows-from-one-data-frame-that-are-not-present-in-a-second-data-frame
'programing' 카테고리의 다른 글
MariaDb가 기존 행에 검사 제약 조건을 적용하지 않음 (0) | 2023.06.06 |
---|---|
튜플에서 하나의 값 가져오기 (0) | 2023.06.06 |
Git를 누르기 전에 여러 커밋 결합 (0) | 2023.06.06 |
PDF에서 페이지를 JPEG로 추출 (0) | 2023.06.06 |
브라우저를 통해 mongodb에 액세스할 수 없음 - 네이티브 드라이버 포트에서 HTTP를 통해 MongoDB에 액세스하려고 하는 것 같습니다. (0) | 2023.06.06 |