【问题标题】:minimum distance function between strings字符串之间的最小距离函数
【发布时间】:2016-08-14 16:51:21
【问题描述】:

完全编辑,非常感谢 shayaa 的建议!

在矩阵中的句子中(从 csv 读取),应检测到存储在列表中的单词(从 txt 读取)。

sentences_list <- matrix(c(
    "this screen is great", 
    "this camera is not bad", 
    "everything good but the camera is awesome",
    "everything bad but the camera is awesome",
    "battery is ok but the camera is awesome"), ncol = 1)

word_list_one <-list("screen", "camera", "battery")
word_list_two <-list("good", "great", "awesome")
word_list_three <-list("bad", "awful", "poor")
word_list_four <-list("not", "don't", "neither")

    one <- apply(sentences_list, 2, function(x) {
        str_detect(x, paste(word_list_one, sep = '|', collapse = '|'))
    })

    two <- apply(sentences_list, 2, function(x) {
      str_detect(x, paste(word_list_two, sep = '|', collapse = '|'))
    })

    three <- apply(sentences_list, 2, function(x) {
      str_detect(x, paste(word_list_three, sep = '|', collapse = '|'))
    })

    four <- apply(sentences_list, 2, function(x) {
      str_detect(x, paste(word_list_four, sep = '|', collapse = '|'))
    })

可以使用以下代码来查看匹配的单词。 (结果是存储而不是直接显示,因为结果的数量是在事后以某种方式统计的)

row=5

print(sentences_list[row])
c(str_extract(sentences_list[row], paste(word_list_one, sep = '|', collapse = '|')))
c(str_extract(sentences_list[row], paste(word_list_two, sep = '|', collapse = '|')))
c(str_extract(sentences_list[row], paste(word_list_three, sep = '|', collapse = '|')))
c(str_extract(sentences_list[row], paste(word_list_four, sep = '|', collapse = '|')))

对于row=1row=2,一切正常,但不适用于以下情况。这是因为只返回来自word_list_x 的句子中的第一个匹配项。我希望代码执行的操作是返回word_list_x 的单词,它与另一个word_list_ 中的单词距离最近。

所以对于row=3in sentences_listword_list_two = "good" 的结果,因为它首先被找到。结果应该是word_list_two = "awesome",因为在row=3 的句子中它更接近word_list_one = "camera" 中的结果。

对于row=4in sentences_listword_list_three = "bad"word_list_two = "awesome" 的结果。因为word_list_two 的结果与word_list_one = "camera" 中的结果的距离更近,所以应该只返回word_list_two = "awesome" 的结果而留下word_list_three = " "blank。

至于row=5in sentences_list 的结果为word_list_one = "battery",因为它是先找到的。结果应该是word_list_one = "camera",因为在row=5 的句子中它更接近word_list_two= "great" 中的结果。

显然,作为一个新手,我对那个项目的规模完全过度紧张,我非常感谢您提供的任何帮助,非常感谢!

【问题讨论】:

  • 仅供参考,这不是一个可重现的例子。我无法从头到尾运行您的代码并重现您的结果。我没有带有单词列表的df。总的来说,data.frame 并不是存放您的话的最佳存储库。一个向量是。对于许多单词向量,您需要使用列表。也许您可以再次编辑此问题。
  • 非常感谢您的建议,非常感谢!我对 R 和 stackoverflow 仍然很陌生。稍后我将尝试根据可重现的示例来改进这个问题。我对所有存储库并不十分熟悉,但我设法提供了我想在文本中找到的单词列表。至于文本,我不知道如何在我的 csv 文件中读取每个元素的多个句子,而不是 data.frame 或矩阵。矩阵可以吗?
  • 嗨@dennis,我有一个简单的问题,如果sentences_list 的最后一个元素是例如“电池很好但相机很棒”,结果会是什么?在这种情况下,您可以检测到来自word_list_one 的两个不同单词的距离:“camera”和“battery”,并且两者都会在相同距离处有来自word_list_two 的单词:“good”和“awesome”。跨度>
  • 抱歉回答晚了,刚刚收到邮件。。只要找到 word_list_one 中的两个单词,并且 word_list_two/ 3 中也有两个单词,并且它们之间的距离完全相等,比它应该在发生时简单地计算:)

标签: r


【解决方案1】:

好的,这就是我想出的。我采取了一种方法,结果是data.frame,其中第一列包含第一个列表中的一个单词,其他列“二”、“三”和“四”包含每个列表中最接近的单词到第一列中的单词。首先,计算最小距离的两个函数:

getMinimumDistanceWord <- function(text, word, wordList){
  min <- " "
  minDist <- 1000
  for (w in wordList){
    d <- distanceBetweenWords(text, word, w)
    if (d != 0 && d < minDist){
      min <- w
      minDist <- d
    }
  }
  return (list(min, minDist))
}


distanceBetweenWords <- function(text, word1, word2){
  x <- strsplit(text, " ")[[1]]
  dist <- abs(grep(word1, x) - grep(word2, x))
  if (length(dist) == 0) return (0)
  else return (dist)
}

现在,遍历句子列表并计算最小距离:

res <- data.frame(one = character(), two = character(), three = character(), four = character(), stringsAsFactors=FALSE)
i <- 1
for(elem in sentences_list){
  base.word.list <- unlist(str_extract_all(elem, paste(word_list_one, sep = '|', collapse = '|')))
  res[i, 1] <- base.word.list[1]
  res[i, 2] <- getMinimumDistanceWord(elem, base.word.list[1], word_list_two)[1]
  res[i, 3] <- getMinimumDistanceWord(elem, base.word.list[1], word_list_three)[1]
  res[i, 4] <- getMinimumDistanceWord(elem, base.word.list[1], word_list_four)[1]
  if (length(base.word.list) != 1){
    currentDistance2 <- as.numeric(unlist(getMinimumDistanceWord(elem, base.word.list[1], word_list_two))[2])
    currentDistance3 <- as.numeric(unlist(getMinimumDistanceWord(elem, base.word.list[1], word_list_three))[2])
    currentDistance4 <- as.numeric(unlist(getMinimumDistanceWord(elem, base.word.list[1], word_list_four))[2])
    for(currentWord in base.word.list){
      if (getMinimumDistanceWord(elem, currentWord, word_list_two)[2] < as.numeric(currentDistance2)){
        currentDistance2 <- getMinimumDistanceWord(elem, currentWord, word_list_two)[2]
        res[i, 1] <- currentWord
        res[i, 2] <- getMinimumDistanceWord(elem, currentWord, word_list_two)[1]
      }
      if (getMinimumDistanceWord(elem, currentWord, word_list_three)[2] < as.numeric(currentDistance3)){
        currentDistance3 <- getMinimumDistanceWord(elem, currentWord, word_list_three)[2]
        res[i, 1] <- currentWord
        res[i, 3] <- getMinimumDistanceWord(elem, currentWord, word_list_three)[1]
      }
      if (getMinimumDistanceWord(elem, currentWord, word_list_four)[2] < as.numeric(currentDistance4)){
        currentDistance4 <- getMinimumDistanceWord(elem, currentWord, word_list_four)[2]
        res[i, 1] <- currentWord
        res[i, 4] <- getMinimumDistanceWord(elem, currentWord, word_list_four)[1]
      }
    }
  }
  i <- i+1
}

结果 data.frame 将是这样的:

     one     two three four
1 screen   great           
2 camera           bad  not
3 camera awesome           
4 camera awesome   bad     
5 camera awesome 

例如,第一行表示与单词“screen”(在列表一中)最近的单词是“great”(在列表二中),并且在列表“三”中没有其他最近的单词和“四”。同样,第五行表示最接近“相机”的词(在第五句中)是“真棒”。第二行表示,在第二句中,第三个列表中有一个与“相机”“最近”的词(“bad”),而第四个列表中还有另一个最接近的词(“not”)。

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    为什么不这样

    我编辑了你的数据以便它运行

    df <- c("second" , "word1", "word2", "word3", 
              "word4","first",  "word1", "word2", "third")
    one <- "third"
    two <- c("second", "third")
    

    匹配每个向量

    match1 <-match(one, df)
    match2 <- match(two, df)
    match3 <- match("first",df)
    

    确定最接近您要查找的单词的匹配向量的位置,在本例中为单词“first”

    closest <- which.min(abs(match2 - match3))
    

    现在检查你的答案

    df[match1]
    [1] "third"
    
    df[match2[closest]]
    [1] "third"
    

    编辑以回答您的编辑:

    我会这样做

    library(stringr)
    sentences_list <- list("this screen is great", 
      "this camera is not bad", 
      "everything good but the camera is awesome",
      "everything bad but the camera is awesome",
      "battery is ok but the camera is awesome")
    
    word_list_one <- c("screen", "camera", "battery")
    word_list_two <- c("good", "great", "awesome")
    word_list_three <- c("bad", "awful", "poor")
    word_list_four <- c("not", "don't", "neither")
    
    l <- lapply(sentences_list, str_match_all, word_list_one)
    

    str_match_all 函数将返回一个包含 5 个列表的列表,每个列表包含三个元素。 l 中的第一个列表返回第一个单词列表中的匹配项以及匹配的单词。

    这与在原始矩阵中保存它们并使用相同

    apply(sentences_list,1, str_match_all, word_list_one)
    

    您应该能够使用我提供的原始答案来完成示例。

    【讨论】:

    • 非常感谢您的回答!我让它适用于您最近编辑的部分。对于您提供的原始答案的以下实现,我并没有真正让代码工作。我现在将match1 等作为NA NA NA NA NA。对于您提供的两个选项,所以 applylapply 除此之外,我真的不明白您对 match 和最接近所做的事情。
    猜你喜欢
    • 2019-12-10
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    相关资源
    最近更新 更多