如何快速查找同义词并从查找表返回最高顺序的同义词?

时间:2017-11-03 12:33:39

标签: r loops match

我想创建一个函数,它接受一个字符串列表,并将它们与包含多个(> 100)列的数据框中的字符串进行匹配。然后将所有匹配的字符串返回到新的数据帧中。换句话说,函数开始在col1中查找string1并在找到时停止。如果string4没有在col1中找到它,但在col2中,所以它只返回string2。如果是字符串3,它会停止,但string6会返回string3。

strings<-c("string1", "string2", "string3", "string4", "string5", "string6")

DF

col1    col2    col3
string1 x   x
string2 string4 x
string3 string5 string6

dput(DF)

structure(list(col1 = structure(1:3, .Label = c("string1 x   x", 
"string2 string4 x", "string3 string5 string6"), class = "factor"), 
    col2 = c(NA, NA, NA), col3 = c(NA, NA, NA)), .Names = c("col1", 
"col2", "col3"), class = "data.frame", row.names = c(NA, -3L))

df_new

col_combo
string1
string2
string3
string2
string3
string3

1 个答案:

答案 0 :(得分:1)

您在上次评论中提示您正在寻找查找同义词的函数,这有助于提供答案。以下答案肯定不是最优雅的,也不是最快的。如果要查找大量同义词,可以查看data.table的解决方案,这是此类查找任务的最快包。但是,为了让你前进,我只会使用基础R.(请注意,我已经重写了你的数据,因为你的df结构对我没有意义,我希望我对你的数据的理解是正确的。)< / p>

更新:根据折叠行中的搜索引入了其他选项,其中一个包含'stringi'包和一个data.table appraoch。还添加了一个不匹配的"string7"。此外,使用microbenchmark引入了基准。我的data.table方法似乎不是最好的,此外,该软件包带来了小数据集的一定开销,只有较大的数据集才具有明显的速度优势。您可以提供更大的可重现示例,可能基于此问题link中使用的函数,以便更好地进行比较。但是,应该注意的是,data.table对于精确匹配可能更快,请检查?%like%。我测试的其他功能必须进行公平比较,也可以使用包fmatch

strings <- c("string1", "string2", "string3", "string4", "string5", "string6", "string7")

df <- read.table(text = "col1    col2    col3
                 string1 x   x
                 string2 string4 x
                 string3 string5 string6"
                 ,stringsAsFactors = F,header =T)


find_synonyms <- function(df, strings) {

  sapply(strings, function(x) {

    synonyms <- apply(df, 1, function(y) {
      #you could also use match()
      #grep() allows partial matching if needed
      if(any(grepl(paste0("^",x,"$"), y))) {           
        y[1]            
      }  else {            
        NA            
      }       
    })
    synonyms[!(is.na(synonyms))]
  }) 
}


find_synonyms_collapse_rows_grepl <- function(df, strings) {

  synsets <- apply(df, 1, paste, collapse = " ")
  names(synsets) <- df[,1]

  sapply(strings, function(x) {

    names(synsets)[grep(paste0("\\b", x ,"\\b"), synsets, perl=T)]  

  })
}


library(stringi)
find_synonyms_collapse_rows_stringi <- function(df, strings) {

  synsets <- apply(df, 1, paste, collapse = " ")
  names(synsets) <- df[,1]

  sapply(strings, function(x) {

    names(synsets)[stri_detect_regex(synsets, paste0("\\b", x ,"\\b"))]  

  })
}


library(data.table)
find_synonyms_DT_reshape_like <- function(df, strings) {

  df <- as.data.table(df)
  df[ , mainsynonym := col1]
  df <- melt(df, id.vars = "mainsynonym")
  setkey(df, value)

  sapply(strings, function(x) {

    df[value %like% x, mainsynonym]

  })
}

find_synonyms_DT_matchkey <- function(df, strings) {

  df <- as.data.table(df)
  df[ , mainsynonym := col1]
  df <- melt(df, id.vars = "mainsynonym")
  setkey(df, value)

  sapply(strings, function(x) {

    df[value == x , mainsynonym]

  })
}


results_list <- list(unlist(find_synonyms(df, strings)),
                     unlist(find_synonyms_collapse_rows_grepl(df, strings)),
                     unlist(find_synonyms_collapse_rows_stringi(df, strings)),
                     unlist(find_synonyms_DT_reshape_like(df, strings)),
                     unlist(find_synonyms_DT_matchkey(df, strings))
                     )

sapply(results_list, function(x) {

  sapply(results_list, function(y) {

    identical(x,y)
  })

}
)
# [,1] [,2] [,3] [,4] [,5]
# [1,] TRUE TRUE TRUE TRUE TRUE
# [2,] TRUE TRUE TRUE TRUE TRUE
# [3,] TRUE TRUE TRUE TRUE TRUE
# [4,] TRUE TRUE TRUE TRUE TRUE
# [5,] TRUE TRUE TRUE TRUE TRUE


library(microbenchmark)

microbenchmark(
find_synonyms(df, strings),
find_synonyms_collapse_rows_grepl(df, strings),
find_synonyms_collapse_rows_stringi(df, strings),
find_synonyms_DT_reshape_like(df, strings),
find_synonyms_DT_matchkey(df, strings)
)

# Unit: microseconds
# expr      min        lq      mean    median        uq       max neval
# find_synonyms(df, strings)  719.624  848.5085 1129.4298  987.6565 1058.9080  9290.361   100
# find_synonyms_collapse_rows_grepl(df, strings)  660.017  738.1770  952.7571  794.8230  839.4295 16998.577   100
# find_synonyms_collapse_rows_stringi(df, strings)  223.428  265.8625  364.4979  302.9685  344.4170  5798.433   100
# find_synonyms3_DT_reshep_like(df, strings) 3259.029 3643.9060 3900.1955 3800.8180 4102.7985  5883.303   100
# find_synonyms_DT_matchkey(df, strings) 4710.135 4907.9040 5428.8650 5279.5595 5630.8855  8450.769   100