【问题标题】:how to match strings of vectors with dataframe column in R如何将向量字符串与R中的数据框列匹配
【发布时间】:2017-05-19 13:30:54
【问题描述】:

我在 r 中有以下数据框

Id    titles
1     emami paper mills slips 10% on dismal q4 numbers
2     jsw steel q4fy17 standalone net profit rises 173.33%
3     fmcg major hul q4fy17 standalone net profit rises 6.2
4     chennai petroleum, allsec tech slip 6-7% on poor q4

而且,我在向量中有名字

names <- c("emami ltd","jsw steel ltd","abc","hul india ltd","tcs","chennai petroleum corp ltd")

我想将数据框列标题与向量字符串匹配,并在新列中打印相应的字符串。我想要的数据框是

 Id    titles                                                    names
1     emami paper mills slips 10% on dismal q4 numbers           emami ltd
2     jsw steel q4fy17 standalone net profit rises 173.33%       jsw steel ltd
3     fmcg major hul q4fy17 standalone net profit rises 6.2      hul india ltd
4     chennai petroleum, allsec tech slip 6-7% on poor q4        chennai petroleum corp ltd

我正在使用以下代码进行操作,但它并没有给我想要的。

df[grepl(paste(names, collapse="|"), df$titles),]

如何在 R 中做到这一点?

【问题讨论】:

  • 那是因为没有一个标题包含"ltd" 字符串。 IE。在您的第一个标题中只有"emami",而不是"emami ltd"
  • 那么,我该怎么做呢?
  • 我假设您不希望查找中的 "ltd" 正确?
  • 不,我不想要那个。
  • 第三个不对吗?例如,您要仅匹配 "hul india" 还是 hulindia

标签: r


【解决方案1】:

如果我理解正确的话,您可以使用 BaseR 的 gregexpr 以及 regematchesgsub 来完成您的任务。

数据:在 OP 更改问题后编辑

options(stringsAsFactors = F)
df <- data.frame(titles = c("emami paper mills slips 10% on dismal q4 numbers",
                            "jsw steel q4fy17 standalone net profit rises 173.33%",
                            "fmcg major hul q4fy17 standalone net profit rises 6.2",
                            "chennai petroleum, allsec tech slip 6-7% on poor q4"),stringsAsFactors = F)

names <- c("emami ltd","jsw steel ltd","abc","hul india ltd","tcs","chennai petroleum corp ltd")

正则表达式

library(dplyr)
library(stringr)

newnames <- gsub("^(\\w+).*","\\1",names)
regmat <- regmatches(df$titles,gregexpr(paste0(newnames,collapse="|"),df$titles))
regmat[lapply(regmat,length) == 0] <- NA
df <- data.frame(cbind(df,newnames =do.call("rbind",regmat)),stringsAsFactors = F)
df1 <- data.frame(names=names,newnames=newnames,stringsAsFactors = F)
left_join(df,df1,by="newnames")

您也可以使用stringr 库,如下所示:

library(stringr)
newnames <- str_replace(names,"^(\\w+).*","\\1")
df$newnames <- str_extract(df$titles,paste0(newnames,collapse="|"))
df1 <- data.frame(names=names,newnames=newnames,stringsAsFactors = F)
left_join(df,df1,by="newnames")

输出

    > left_join(df,df1,by="newnames")
                                                 titles newnames                      names
1      emami paper mills slips 10% on dismal q4 numbers    emami                  emami ltd
2  jsw steel q4fy17 standalone net profit rises 173.33%      jsw              jsw steel ltd
3 fmcg major hul q4fy17 standalone net profit rises 6.2      hul              hul india ltd
4   chennai petroleum, allsec tech slip 6-7% on poor q4  chennai chennai petroleum corp ltd

【讨论】:

  • 当我给出以下名称 names &lt;- c("emami","jsw steel","abc","tcs") 并运行您的代码时保持 df 如上所述。它抛出一个错误Error in $(*tmp*, "newnames", value = c("emami", "jsw steel" : replacement has 2 rows, data has 3
  • @Neil 你的向量中缺少“hul india ltd”,它在两个系统上测试不会出错。
  • @Neil ,我在 stringr 上添加了另一个解决方案,你也可以检查一下
  • 我的许多名字都包含gujarat state petronet,hcl infosystems,hester pharm,high ground enterprise,您的代码无法识别这些。 1str_replace(names,"^(\\w+).*","\\1") 此代码删除空格后的文本。
  • 感谢您的回答。我把它纠正了。赞赏
【解决方案2】:

从你的名字中删除 ltd :

names <- gsub(" ltd","",names)

【讨论】:

    【解决方案3】:

    也可以使用sqldf 进行这种“模糊”合并。

    构造查找:

    names <- data.frame(name = c("emami ltd","jsw steel ltd","abc","hul india ltd","tcs"))
    names$lookup <- gsub("(\\w+).*", "\\1", names$name)
    

    执行合并:

    library(sqldf)
    res <- sqldf("SELECT l.*, r.name
           FROM df as l
           LEFT JOIN names as r
           ON l.titles LIKE '%'||r.lookup||'%'")
    

    一些注意事项:我从查找中提取了第一个单词,因为您说您只想要"hul",而不是"hul india"。同样在sql 中,|| 表示连接,% 表示通配符(它将匹配任何内容),因此如果任何查找出现在文本中的任何位置,无论它之前或之后是什么,这将匹配。


    使用Reduce 然后合并的另一个选项是:

    df$lookup <- Reduce( function(x, y) {x[grepl(y,x)] <- y; x}, c(list(df$titles), names$lookup))
    merge(df, names)
    

    【讨论】:

      【解决方案4】:

      为了添加到之前的答案,我制作了一个函数,包括之前的一些 cmets:

      df <-  data.frame(title=c("emami paper mills slips 10% on dismal q4 numbers",
                                  "jsw steel q4fy17 standalone net profit rises 173.33%",
                                  "fmcg major hul q4fy17 standalone net profit rises 6.2"))
      
      
      names <- c("emami ltd","jsw steel ltd","abc","hul india ltd","tcs")
      
      find_string <- function(data,names){
      
          ### Clean the names 
          newnames <- gsub("^(\\w+).*","\\1",names)
      
          ### Loop over the names to find which sentence contain it
          for(i in 1:length(newnames)){
      
              if(length(grep(newnames[i],df$title)) != 0){
                  df$names[grep(newnames[i],df$title)] <- newnames[i]
      
              }else{
                  print(paste(names[i],"not found in the data!"))
              }
          }
          return(df)
      }
      
      ### Run the function
      
      find_string(df,names)
      

      希望这会有所帮助!

      【讨论】:

      • 您的代码没有给出预期的内容。您的 for 循环似乎有问题。
      • 您只需将结果存储在一个新的数据框中... new
      猜你喜欢
      • 2019-04-10
      • 1970-01-01
      • 2021-12-16
      • 2018-07-10
      • 1970-01-01
      • 2016-03-23
      • 2012-11-25
      • 1970-01-01
      • 2017-11-10
      相关资源
      最近更新 更多