【问题标题】:Searching for a string within a column for merging in r在列中搜索字符串以在 r 中合并
【发布时间】:2019-04-25 07:00:20
【问题描述】:

我想在数据框中的列中搜索来自不同数据框的列中的字符串,然后将它们合并在一起。例如:

我有这个数据框:

    location
1   2 high street, ca
2   24 long street, ba,UK
3   1 first avenue, ab
4   15 nant peris , ac
5   1 high street
6   second avenue, ca, UK

那我要在这个数据集上进行匹配:

   id      block
1  1        ab
2  2        ac
3  3        ab
4  5        cb
5  4        ba
6  2        ca

所以我想在“位置”中搜索“块”列中的任何值,然后将列块和 id 合并到第一个数据集上,这样合并后的数据集如下所示:

    location              id     block
1 2 high street, ca       2       ca
2 24 long street, ba,UK   4       ba
3 1 first avenue, ab      1       ab
4 15 nant peris , ac      2       ac
5 1 high street           NA      NA
6 second avenue, ca,UK    2       ca

可重现的代码:

df1<-data.frame(id = factor(c(1,2,3,5,4,2)), block = c('ab','ac','ab','ca','ba','ca'))
df2<-data.frame(location = c('2 high street, ca','24 long street, ba, UK','1 first avenue, ab', '15 nant peris , ac','1 high street','second avenue, ca, UK'))

【问题讨论】:

  • 您的第二个数据框有问题,因为块ca 与两个不同的值相关联。没有直接的方法可以加入并获得您想要的预期输出。
  • 对不起,这是我现在纠正的类型!

标签: r search merge substring


【解决方案1】:

这是使用sqldf 包的一种方法:

library(sqldf)
sql <- "SELECT t1.location, t2.id, t2.block
        FROM df1 t1
        LEFT JOIN df2 t2
            ON t1.location LIKE '%, ' || t2.block OR
               t1.location LIKE '%, ' || t2.block || ',%';
results <- sqldf(sql)

我相信sqldf 包在 SQLite 上运行,这里是使用您的数据运行 SQLite 演示的链接:

Demo

【讨论】:

  • sqldf 使用 sqlite、h2、mysql 和 postgresql 后端运行,但默认后端是 sqlite。
【解决方案2】:

使用查找表ltbl的解决方案,(名称向量)

ltbl = 1:4  # lookup Table
names(ltbl) = c('ab','ac','ca','ba')

#ab ac ca ba 
# 1  2  3  4

new<-
do.call(
    rbind,
    apply(df2, 1, function(x) {
        ans <- names(ltbl)[stringr::str_detect(x, paste0("\\b", names(ltbl), "\\b"))]
        cbind.data.frame( id = I(ltbl[ans]), block = I(ans) )[1,]
    })
)


cbind(df2, new)

#                  location id block
#ca       2 high street, ca  3    ca
#ba  24 long street, ba, UK  4    ba
#ab      1 first avenue, ab  1    ab
#ac      15 nant peris , ac  2    ac
#NA           1 high street NA  <NA>
#ca1  second avenue, ca, UK  3    ca

将您的长块转换为该查找表:

示例:每个 id 只能有一个块,Tim 已经解决了这个问题

myLongCrasyBlock <- data.frame(id = factor(c(1:3,1:3)), block = c('ab','ac','ab','ab','ac','ab'))

myLongCrasyBlock <- unique(myLongCrasyBlock)
ltbl             <- `names<-`(myLongCrasyBlock$id, myLongCrasyBlock$block)

【讨论】:

  • 我发现这很难使用,因为我在 Block 中有超过 4 个选项,实际上我有超过 2000 个我只是为了堆栈溢出而简化它。任何方式我都可以使用它而不列出 names(ltbl) = 中的所有“块”?
  • 这是一个不同的问题,看这里 block = c('ab','ac','ab','ab','ac','ab')) 你列出了所有的块选项,我这里有2000多个选项,我不能每个都输入。
【解决方案3】:

我试图使用您的可重现代码找到不需要特殊包的解决方案。

# Creating dataframes
  df1<-data.frame(id = factor(c(1,2,3,5,4,2)), block = c('ab','ac','ab','ca','ba','ca'))
  df2<-data.frame(location = c('2 high street, ca','24 long street, ba, UK','1 first avenue, ab', '15 nant peris , ac','1 high street','second avenue, ca, UK'))

# Make some varaibles as character
  df1$block <- as.character(df1$block)
  df2$location <- as.character(df2$location)

# Create new variable as block        
  df2$block <- "NA"

# Starting the loop
  for (i in 1:length(df1$block)) {

    x <- grep(df1$block[i], df2$location, value = T) #Find location values with the same block value 

    y <- df2[df2$location %in% x,] #Create a new dataframe only with the values found

    rowstokeep <- which(rownames(df2) %in% rownames(y)) # Get the rows of those values

    df2$block[rowstokeep] <- df1$block[i] # Input the block value in the correspond location value
  }

# Merge by "block" variable to get the ID        
       df3 <- merge(df1, df2, by.x = "block", by.y = "block")

希望对你有用

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-05
    • 1970-01-01
    • 2017-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-28
    • 1970-01-01
    相关资源
    最近更新 更多