比较两个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
有关所有连接选项和设置主题的详细描述,这是我见过的最好的摘要之一: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命令,用于快速检查
你可以使用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输出:
使用diffobj
包:
library(diffobj)
diffPrint(a1, a2)
diffObj(a1, a2)
R语言ggplot2可视化将两个dataframe可视化的结果组合在一起实战:combining two plots from different data.frames
ggplot 在不同的 data.frames 中带有 x 和 y 变量,带有 For-Loop