比较两个数据框并在R

时间:2018-11-09 12:53:49

标签: r dataframe compare

我对R还是很陌生,我正在尝试解决看似很简单的问题,但是我不确定该怎么做。我正在尝试比较两个数据框,并打印出其中一个而不是另一个的行,并且还打印另一个列表/数据框,其中只有一个单元格已被更新。

df1
firstname  lastname email
Grace       Holly   hollyoaks@yahoo.com
Trish       Edison  edisontrish@gmail.com

df2
firstname lastname  email
Grace     Holly     rickyoaks@yahoo.com
Frederick Sam       sammic@gmail.com

我想做的第一件事是获取df2中而不是df1中的行,这就是我的方法:

require(sqldf)

df2NotIndf1 <- sqldf('SELECT * FROM df2 EXCEPT SELECT * FROM df1')

这给了我输出:

`firstname lastname  email`
`Frederick Sam       sammic@gmail.com`

现在,我想要的是一种通过注意到名字和姓氏相同但电子邮件地址不同的方式来获得第一行作为其自身输出的方法。

所以,我想要一种打印方法:

firstname  lastname  email

Grace     Holly     rickyoaks@yahoo.com

我已经看过compare()函数,以及merge和其他函数,但是它们似乎是在比较不同的行而不是不同的单元格。

2 个答案:

答案 0 :(得分:2)

首先,我创建数据框。

# Create data frames
df1 <- read.table(text = "firstname  lastname email
                  Grace       Holly   hollyoaks@yahoo.com
                  Trish       Edison  edisontrish@gmail.com", ,
                  header = TRUE, stringsAsFactors = FALSE)

df2 <- read.table(text = "firstname lastname  email
Grace     Holly     rickyoaks@yahoo.com
Frederick Sam       sammic@gmail.com", 
                  header = TRUE, stringsAsFactors = FALSE)

接下来,我加载dplyr

# Load libraries
library(dplyr)

在这里,我执行一个反联接来查找df2中不在df1中的行。

# Perform antijoin
df3 <- df2 %>% anti_join(df1, by = c("firstname", "lastname"))

#   firstname lastname            email
# 1 Frederick      Sam sammic@gmail.com

然后,我将原始的两个数据帧绑定在一起,删除先前标识为仅出现在df2中的行,然后使用除一个以外的所有列检查重复项。如果除第一列外所有列中都有重复项,我将保留这些行。

# Bind two data frames together
# Remove those only appearing in df2
# Filter to those with duplicates in all but one column
df1 %>% 
  bind_rows(df2) %>% 
  anti_join(df3) %>% 
  filter((duplicated(firstname, lastname) + duplicated(email, lastname) + duplicated(firstname, email)) == ncol(df1) - 1)

#   firstname lastname               email
# 1     Grace    Holly rickyoaks@yahoo.com

我目前正在考虑一种更简洁的编写filter行的方法,该行可以推广到任意数量的列。

答案 1 :(得分:1)

1)如果您正在寻找一种列出姓氏和名字同时在df1和df2中但电子邮件地址不同的人的方法,

sqldf("select df1.*, df2.email email2 
  from df1 
  join df2 on df1.firstname = df2.firstname and 
              df1.lastname = df2.lastname and 
              df1.email <> df2.email")

给出以下内容,其中显示了df1记录和与df2不同的电子邮件。

  firstname lastname               email              email2
1     Grace    Holly hollyoaks@yahoo.com rickyoaks@yahoo.com

2)或基本解决方案是:

subset(merge(df1, df2, by = 1:2), email.x != email.y)

注意

可重复使用的输入为:

Lines1 <- "firstname  lastname email
Grace       Holly   hollyoaks@yahoo.com
Trish       Edison  edisontrish@gmail.com"

Lines2 <- "firstname lastname  email
Grace     Holly     rickyoaks@yahoo.com
Frederick Sam       sammic@gmail.com"

df1 <- read.table(text = Lines1, header = TRUE, as.is = TRUE, strip.white = TRUE)
df2 <- read.table(text = Lines2, header = TRUE, as.is = TRUE, strip.white = TRUE)