根据两个相似df的对比创建一个新的dataframe

Create a new dataframe according to the contrast between two similar df

我有一个这样制作的数据框:

  X Y  Z T
  1 2  4 2
  3 2  1 4
  7 5 NA 3

经过几个步骤(哪个不重要)我得到了这个 df:

  X Y Z T
  1 2 4 2
  3 2 NA 4
  7 5 NA 3

我想获得一个新的数据框,仅由行在步骤中没有改变;结果将是这个:

 X  Y  Z  T
 1  2  4  2
 7  5  NA 3

我该怎么办?

base R 的一个选项是 paste 每个数据集的行放在一起并比较 (==) 以创建我们用于子集化新数据集的逻辑向量

dfO[do.call(paste, dfO) == do.call(paste, df),]
#   X Y  Z T
#1 1 2  4 2
#3 7 5 NA 3

其中 'dfO' 是旧数据集,'df' 是新数据集

你可以使用dplyr的intersect函数:

library(dplyr)
intersect(d1, d2)
#  X Y  Z T
#1 1 2  4 2
#2 7 5 NA 3

这是基本 R 的 intersect 函数的 data.frame 等价物。

如果您正在使用 data.tables,该软件包还提供这样的功能:

library(data.table)
setDT(d1)
setDT(d2)
fintersect(d1, d2)
#   X Y  Z T
#1: 1 2  4 2
#2: 7 5 NA 3

另一个dplyr解决方案:semi_join.

dt1 %>% semi_join(dt2, by = colnames(.))
  X Y  Z T
1 1 2  4 2
2 7 5 NA 3

数据

dt1 <- read.table(text = "X Y  Z T
  1 2  4 2
  3 2  1 4
  7 5 NA 3",
                  header = TRUE, stringsAsFactors = FALSE)

dt2 <- read.table(text = "  X Y Z T
  1 2 4 2
                  3 2 NA 4
                  7 5 NA 3",
                  header = TRUE, stringsAsFactors = FALSE)

恐怕 semi joinintersectmerge 都不是正确答案。 mergeintersect 将无法正确处理重复行。半连接将改变行的顺序。

从这个角度来看,我认为目前唯一正确的是akrun的。

你也可以这样做:

df1[rowSums(((df1 == df2) | (is.na(df1) & is.na(df2))), na.rm = T) == ncol(df1),]

但我认为akrun的方式更优雅,并且在速度方面可能表现得更好。