【问题标题】:Compare two dataframes and print out updated rows in R比较两个数据帧并在 R 中打印出更新的行
【发布时间】:2018-11-09 12:53:49
【问题描述】:

我对 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 和其他函数,但它们似乎是在比较不同的行,而不是不同的单元格。

【问题讨论】:

    标签: r dataframe compare


    【解决方案1】:

    首先,我创建数据框。

    # 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 行,该行泛化到任意数量的列。

    【讨论】:

    • 这太好了,谢谢。基于我发现的类似问题,我还尝试了另一种解决方案:
    • 我还尝试了另一种解决方案,基于我发现的一个类似问题:email_change &lt;- anti_join(df2, df1) email_update_only &lt;- inner_join(email_change, df2, by = c("firstname", "lastname"), suffix = c(".df1", ".df2")) %&gt;% filter(email.df2 != email.df1) 它解决了两个问题,关于查找不在另一个数据框中的行,以及只选择行电子邮件作为差异。不过,您的解决方案更整洁:)
    【解决方案2】:

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-23
      • 2017-04-26
      • 2021-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-07
      相关资源
      最近更新 更多