我在R中有两个具有相同列和数据的数据帧。每个数据类型。有些专栏是以文字为基础的。其他人是数字&其他一些是约会。但是,相同的列在两个数据帧中都具有相同类型的数据。两者中的唯一标识符也是相同的,即主键匹配。
现在,我想创建一个第三个数据帧,它基本上捕获每个主键,DF1和DF2中相应列的值之间的差异是什么。当要检查的列是字符时,我们可以简单地说1或0表示差异。当它是数字时,我们可以捕获差异量,或者可能只是1或0。
在R中执行此操作的最有效方法是什么?我不想逐行比较,因为它很慢。逐列比较会很好,但这似乎也需要太多的手动监督。理想情况下,寻找一些可以帮助我做到这一点的数据框级功能。
可重复的&可编辑的例子:
Dataframe1:
ID val1 date1 chrval1 val3
A1 400 3/4/2017 DR9912YS -43
A2 230 3/4/2017 ER9F4YS -43
A3 500 31/2/2015 FFR99S -49
Dataframe2:
ID val1 date1 chrval1 val3
A1 400 3/4/2017 DR9912YS -43
A2 400 3/4/2017 DR9912YS -43
A3 400 31/4/2017 DR9912YS -43
Ideally this is what I am looking for:
Difference Dataframe:
ID val1 date1 chrval1 val3
A1 0 0 True 0
A2 170 0 False 0
A3 -100 0/2/2 False 5
答案 0 :(得分:0)
快点煮熟的东西。它不处理日期案例。
我正在使用库gtools中的宏。我不确定这是否有必要,但我的思绪就是这样。
library(gtools)
表格。 read.table
非常适合轻松复制数据。
aa <- read.table(header=TRUE,text="
ID val1 date1 chrval1 val3
A1 400 3/4/2017 DR9912YS -43
A2 230 3/4/2017 ER9F4YS -43
A3 500 31/2/2015 FFR99S -49")
bb <- read.table(header=TRUE,text="
ID val1 date1 chrval1 val3
A1 400 3/4/2017 DR9912YS -43
A2 400 3/4/2017 DR9912YS -43
A3 400 31/4/2017 DR9912YS -43")
这是一个执行以下操作的简单宏。如果fn1
产生错误,它将捕获它并使用fn2
。可能不是
最合适的方式。随时改进。
expect_error <- defmacro(fn1,fn2,expr={
tryCatch({fn1(x,y)},
error=function(e) {mytc(fn2(x,y))}
)})
它也存储了这个功能。根据暴击使用fn1
或fn2
。
例如crit=is.numeric
。如果暴击是真的fn1
,则使用fn2
。
condlapply <- function(lst, crit, fn1, fn2){
lapply(lst, function(x) if(crit(x)) {
fn1(x)} else {fn2(x)})
}
一些简单的功能
myequal <- function(x,y=1){
`==`(x,y)
}
mydiff <- function(x,y){
`-`(x,y)
}
res <- data.frame(sapply(Map(function(x,y) expect_error(mydiff,myequal),aa,bb),c))
在这里偷了ID。
res$ID <- aa$ID
## res
## ID val1 date1 chrval1 val3
## 1 A1 0 1 1 0
## 2 A2 -170 1 0 0
## 3 A3 100 0 0 -6
我们可以结束一个函数
check_df <- function(df1,df2){
### DD
## df1, df2 . data.frames
res <- data.frame(sapply(Map(function(x,y) expect_error(mydiff,myequal),df1,df2),c))
res$ID <- aa$ID
res
}
答案 1 :(得分:0)
在基地R:
# merge the two dataframes
dfm <- merge(df1, df2, by = 'ID')
# create numeric vectors for the column-names ending with '.x' and '.y'
xvec <- grep('.x', names(dfm), fixed = TRUE)
yvec <- grep('.y', names(dfm), fixed = TRUE)
# determine which columns are not of the character class
non_char <- which(sapply(dfm, class) != 'character')
# create a new dataframe by binding the 'ID' column
# with the difference of the '.x' & '.y' columns
dfnew <- cbind.data.frame(ID = dfm$ID,
dfm[, intersect(yvec, non_char)] - dfm[, intersect(xvec, non_char)],
chrval1 = dfm$chrval1.x == dfm$chrval1.y)
# remove the '.y' from the column-names of the new dataframe
names(dfnew) <- gsub('.y','',names(dfnew),fixed=TRUE)
给出:
> dfnew
ID val1 date1 val3 chrval1
1 A1 0 0 days 0 TRUE
2 A2 170 0 days 0 FALSE
3 A3 -100 733 days 6 FALSE
关于内存效率和速度,data.table
- 包可能是最好的选择。然后你可以这样做:
library(data.table)
setDT(df1)
setDT(df2)
df1[df2, on = 'ID', `:=` (val1 = i.val1 - x.val1,
dat1 = as.numeric(i.date1) - as.numeric(x.date1),
chrval1 = i.chrval1 == x.chrval1,
val3 = i.val3 - x.val3)][, date1:= NULL][]
给出:
> df1
ID val1 date1 chrval1 val3
1: A1 0 1970-01-01 TRUE 0
2: A2 170 1970-01-01 FALSE 0
3: A3 -100 1972-01-04 FALSE 6
使用过的数据:
df1 <- structure(list(ID = c("A1", "A2", "A3"),
val1 = c(400L, 230L, 500L),
date1 = structure(c(17290, 17290, 16557), class = "Date"),
chrval1 = c("DR9912YS", "ER9F4YS", "FFR99S"),
val3 = c(-43L, -43L, -49L)),
.Names = c("ID", "val1", "date1", "chrval1", "val3"), row.names = c(NA, -3L), class = "data.frame")
df2 <- structure(list(ID = c("A1", "A2", "A3"),
val1 = c(400L, 400L, 400L),
date1 = structure(c(17290, 17290, 17290), class = "Date"),
chrval1 = c("DR9912YS", "DR9912YS", "DR9912YS"),
val3 = c(-43L, -43L, -43L)),
.Names = c("ID", "val1", "date1", "chrval1", "val3"), row.names = c(NA, -3L), class = "data.frame")