【问题标题】:Matching columns in 2 data frames when numbers don't exactly match当数字不完全匹配时匹配 2 个数据框中的列
【发布时间】:2019-07-17 09:38:56
【问题描述】:

当我比较的值不完全相同时,如何匹配两个不同的数据框?

我正在考虑使用merge(),但我不确定。

表1:

ID           Value.1
10001        x
18273-9      y
12824/5/6/7  z
10283/5/9    d

表2:

ID           Value.2
10001        a
18274        b
12826        c
10289        u

如何根据 ID 合并表 1 和表 2?

我会使用fuzzyjoin 包的哪个特定功能,尤其是在“/”和“-”的情况下?如何从 18273-9 扩展“-”大小写,以便 R 注册 18273 / 18274 / 18275 / ...?

【问题讨论】:

标签: r database


【解决方案1】:

您可以编写一个函数,从包含“/”或“-”的字符串中提取相应的序列,并将它们重新组合成一个新的data.frame,如下所示:

df1 <- data.frame(ID=c("10001","18273-9","15273-8", "15170-4",  "12824/5/6/7","10283/5/9"), 
                  value=c("a","c","c", "d","k", "l"), stringsAsFactors = F)

df2 <- data.frame(ID=c("10001","18274","12826","10289"), 
                  value=c("o","p","q","r"), stringsAsFactors = F)

doIt <- function(df){
  listAsDF <- function(l) {
    x <- stack(setNames(l, temp$value))
    names(x) <- c("ID", "value")
    return(x)
  }
  Base <- df[!grepl("\\/", df$ID) & !grepl("\\-", df$ID), ]
  #1 cases when - present
  temp <- df[grep("\\-", df$ID),]
  temp <- listAsDF(lapply(strsplit(temp$ID, "-"), function(e) seq(e[1], paste0(strtrim(e[1], nchar(e[1])-1), e[2]), 1)))
  Base <- rbind(Base, temp)
  #2 cases when / present
  temp <- df[grep("\\/", df$ID),]
  temp <- listAsDF(lapply(strsplit(temp$ID, "/"), function(a) c(a[1], paste0(strtrim(a[1], nchar(a[1])-1), a[-1]))))
  Base <- rbind(Base, temp)
  return(Base)
}

然后你可以合并df2和df1:

merge(doIt(df1), df2, by = "ID", all.x = T)

希望这会有所帮助!

【讨论】:

  • 这真的很有帮助!我可以知道您为什么将 setNames 与 x 和 temp 一起使用吗?谢谢!
  • setNames 为对象命名并返回对象本身,这就是我想要的,因为我需要堆栈函数中的名称。
  • 您还介意解释strtrim 中的论点吗?我用谷歌搜索了一下,应该只有两个——strtrim(x, width)?太感谢了!!抱歉打扰了,我才刚开始。
  • strtrim 正在将字符串修剪到所需的宽度,就像您说的那样需要两个参数,如果您将代码分开,您会看到,这正是正在发生的事情。 xe[1]/a[1]widthnchar(e[1])-1/nchar(a[1])-1
【解决方案2】:

您可以使用基础 R 中的模糊字符串匹配函数“agrep”。

df1 <- data.frame(ID=c("10001","18273-9","12824/5/6/7","10283/5/9"), 
                  value=c("a","c","d","k"))

df2 <- data.frame(ID=c("10001","18274","12826","10289"), 
                  value=c("o","p","q","r"))

apply(df1, 1, function(x) agrep(x["ID"], df2$ID, max = 3.5))

正如您所见,它很难找到第 4 行的匹配项。因此,在运行 agrep 之前清理您的 ID 变量(例如,取出“/”)可能是有意义的。

【讨论】:

    【解决方案3】:

    一个选项可以包括提取您想要保留的 ID 格式。然后进行合并。

    您可以按如下方式格式化您的 ID 列:

    library(stringr) 
    library(dplyr) 
    

    如果你只想要任何符号之前的数字

    Table1 %>% mutate(ID = str_extract("[0-9]*")) 
    

    如果要保留前5位数字的序列

    Table1 %>% mutate(ID = str_extract("[0-9]{5}"))
    

    这回答了您的第二个问题,但不使用 fuzzyjoin

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-26
      • 2019-03-09
      • 1970-01-01
      • 1970-01-01
      • 2017-05-07
      • 1970-01-01
      • 2022-11-13
      • 1970-01-01
      相关资源
      最近更新 更多