簡體   English   中英

檢查2個數據幀與數字和字符數據之間差異的最有效方法?

[英]Most efficient way to check difference between 2 dataframes with numeric & character data?

我在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

剛剛煮熟的東西。 它不處理日期案例。

我正在使用庫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))}
)})

它也存在這個功能。 根據暴擊使用fn1fn2 例如, 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
    }

在基地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")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM