【问题标题】:Damerau-Levenshtein distance between two vectors两个向量之间的 Damerau-Levenshtein 距离
【发布时间】:2021-03-31 06:25:48
【问题描述】:

两个字符串“abc”和“acb”之间的 Damerau-Levenshtein 距离将为 1,因为它涉及“b”和“c”之间的一个换位。

> stringdist("abc", "acb", method = "dl")
[1] 1

现在假设我有以下两个字符向量:

A = c("apple", "banana", "citrus")
B = c("apple", "citrus", "banana")

我如何计算 A 和 B 之间的 Damerau-Levenshtein 距离,以便结果与“abc”和“acb”之间的距离相同,因为“citrus”和“banana”之间有一个换位?换句话说,如何计算 A 和 B 之间的 Damerau-Levenshtein 距离,以便将每个项目计为字符串中的一个字符?

【问题讨论】:

  • 试试这个(如果我理解你的话,但不确定):abs(match(A, B) - seq_along(A)),这里假设这两个原子向量都包含相同的元素,只是顺序不同,A也是参考
  • 我需要 A 和 B 之间的单个距离 (= 1),而不是 A 中的每对元素和 B 中的元素之间的距离。
  • 取前面表达式的最大值
  • stringdist(paste(substr(A, 1, 1), collapse=""), paste(substr(B, 1, 1), collapse=""), method="dl") ? (顺便说一句,stringdist 不是基本 R 函数,请在您的问题中包含包加载)
  • 我已经添加(并稍后更新)一个答案,该答案应涵盖 Damerau-levenshtein 距离的所有标准情况,其中向量的每个元素都被视为字符串中的单个字符。 :-)

标签: r distance similarity damerau-levenshtein


【解决方案1】:
library(stringdist)
library(tidyr)

A = c("apple", "banana", "citrus")
B = c("apple", "citrus", "banana")

a <- factor(A, levels = union(A,B)) %>% 
  as.numeric() %>% 
  sapply(function(i) letters[i]
         %>% paste0(collapse = "")
  ) %>%
  paste0(collapse = "")

b <- factor(B, levels = union(A,B)) %>% 
  as.numeric() %>% 
  sapply(function(i) letters[i]
             %>% paste0(collapse = "")
         ) %>%
  paste0(collapse = "")

stringdist(a, b, method = "dl")

【讨论】:

    【解决方案2】:

    怎么样

    vecdist <- function(x, y){
      matches <- match(x, y, nomatch = 0)
      nomatch <- matches == 0
      # No match = we need 1 permutation
      # Other matches: Compare index, for each "not inverted" index, (not 3 vs -3) we need 1 permutation
      perm_match <- (matches - seq_along(matches))[!nomatch]
      perm_n <- sum(perm_match != 0) - sum(duplicated(abs(perm_match)))
      sum(nomatch) + perm_n + sum(!y %in% x)
    }
    

    这里的基本思想是:

    1. 检查xy 中的缺失匹配项,反之亦然。每一个都是 1 个排列
    2. 对于余数,我们需要检查匹配索引。这里我使用了一个小技巧,通过使用duplicated(abs(...)) 检查是否有任何字段必须“相互”切换。例如,abcdbadc 是 2 个排列,而 abcdbdca 是 3。

    这与 stringdist 处理单个字符串的方式非常相似。

    A = c("apple", "banana", "citrus")
    B = c("apple", "citrus", "banana")
    vecdist(A, B)
    [1] 1
    A <- c(A, 'pear')
    vecdist(A, B)
    [1] 2
    vecdist(B, A)
    [1] 2
    A <- c('apple', 'banana', 'citrus', 'pear')
    B <- c('pear', 'citrus', 'banana', 'apple')
    vecdist(A, B)
    [1] 2
    vecdist(B, A)
    [1] 2
    A <- c('apple', 'banana', 'citrus', 'pear')
    B <- c('pear', 'citrus', 'apple', 'banana')
    vecdist(A, B)
    [1] 3
    vecdist(B, A)
    [1] 3
    

    【讨论】: