R:搜索类似字符串并返回条件符号

R:搜索类似字符串并返回条件符号,r,similarity,R,Similarity,My df有以下条目: A xxx xxx xxx1 xx1x yyyy gggg 我想根据a列的相似性,根据以下条件,向df的B列添加符号 我将阈值设置为=或>75% 类似的 列A已排序。所以 检查上面的相似性 这是需要的 如果上一个类似,则符号 将从上面的B列复制 如果上一个不同,则 符号将从同一行的A列复制 例如,因为第1行和第2行是相同的。其符号与A列相同。与第3行相同(4个字母中的3个字母具有相同的字母且顺序相同),75%与第1行和第2行相似。B列中的sybmol将从上一列即xx

My df有以下条目:

A
xxx
xxx
xxx1
xx1x
yyyy
gggg
我想根据a列的相似性,根据以下条件,向df的B列添加符号

  • 我将阈值设置为=或>75% 类似的

  • 列A已排序。所以 检查上面的相似性 这是需要的

  • 如果上一个类似,则符号 将从上面的B列复制

  • 如果上一个不同,则 符号将从同一行的A列复制

例如,因为第1行和第2行是相同的。其符号与A列相同。与第3行相同(4个字母中的3个字母具有相同的字母且顺序相同),75%与第1行和第2行相似。B列中的sybmol将从上一列即xxx复制。由于xx1x(第4行)是与第3行相似的4个字母中的2个,因此它将只使用自己的符号,即xx1x。由于yyyy和gggg完全不同,它们将保留自己的sybmol,如A列所示

因此,我的最终结果应该是这样的:

A      B
xxx    xxx
xxx    xxx
xxx1   xxx
xx1x   xx1x
yyyy   yyyy
gggg   gggg
我通过猜测计算出这个相似度%(如果有用于字符串相似度搜索的形式化方法,则不需要使用它),如果有用于检查R中字符串相似度的形式化方法,则可以很好地使用它

您是否介意指导如何使用R高效地添加此符号列?

设置数据:

x=c("xxx", "xxx", "xxx1", "xx1x", "yyyy", "gggg")
守则:

same <- sapply(seq(length(x)-1), 
  function(i)any(agrep(x[i+1], x[1], max.distance=0.25)))
ex <- embed(x, 2)
cbind(A=x, B=c(x[1], ifelse(same, ex[, 2], ex[, 1])))

它为什么有效

一些关键概念和真正有用的功能:

首先,
agrep
使用
Levenshtein编辑距离
测试字符串的相似程度,该距离有效地计算将一个字符串转换为另一个字符串所需的单个字符更改的数量。参数
max.distance=0.25
表示允许25%的图案字符串不同

例如,测试是否有任何原始字符串类似于“xxx”:这将返回1:4:

agrep("xxx", x, max.distance=0.25)
[1] 1 2 3 4
其次,
embed
提供了一种测试滞后变量的有用方法。例如,
embed(x,2)将
x`转换为滞后数组。这使得比较x[1]和x[2]变得很容易,因为它们现在位于阵列中的同一行上:

embed(x, 2)
     [,1]   [,2]  
[1,] "xxx"  "xxx" 
[2,] "xxx1" "xxx" 
[3,] "xx1x" "xxx1"
[4,] "yyyy" "xx1x"
[5,] "gggg" "yyyy"
最后,我使用
cbind
和向量子集将原始向量和新向量缝合在一起


为了在数据帧而不是向量上实现这一点,我将代码转换为一个函数,如下所示:

df <- data.frame(A=c("xxx", "xxx", "xxx1", "xx1x", "yyyy", "gggg"))

f <- function(x){
  x <- as.vector(x)
  same <- sapply(seq(length(x)-1), 
      function(i)any(agrep(x[i+1], x[1], max.distance=0.25)))
  ex <- embed(x, 2)
  c(x[1], ifelse(same, ex[, 2], ex[, 1]))
}
df$B <- f(df$A)
df

     A    B
1  xxx  xxx
2  xxx  xxx
3 xxx1  xxx
4 xx1x xxx1
5 yyyy yyyy
6 gggg gggg

df这里有一个更“基本”的解决方案(经过编辑以修复评论中提出的一些问题):


dat等等,OP不希望B下的第四个条目是'xx1x'吗?是的,他希望,但他也承认他猜到了值
agrep
使用更改含义的正式定义,默认情况下配置为将所有的修改、删除和插入作为一个更改进行计数。因此,在这个例子中有两个变化。这在某种程度上可以在
agrep
的参数中进行配置。有关详细信息,请参阅agrep。感谢您的精彩代码。如果我的输入是df列而不是列表,您是否介意给我一些关于如何修改代码的指导?非常感谢,谢谢。我可能误解了您代码的使用。你能教我怎么解决这个问题吗?>dat-dat$B>tmp-dat$B[1]for(i in 2:length(tmp)){+x=0.75){+dat$B[i]我相信问题在于,我已经配置了R,在创建数据帧时将字符向量作为字符;默认设置是将它们强制为因子。
strsplit
需要一个字符向量,而不是因子。如果使用
strsplit(as.character(dat$a),”)
它应该可以工作。tmp[[I]会发出警告(但没有问题)]==tmp[[i-1]]比较,因为它们有时长度不同。好的,编辑以修复该问题和长度不匹配警告,该警告适用于此特定数据,但一般不适用。现在应该可以了。
df <- data.frame(A=c("xxx", "xxx", "xxx1", "xx1x", "yyyy", "gggg"))

f <- function(x){
  x <- as.vector(x)
  same <- sapply(seq(length(x)-1), 
      function(i)any(agrep(x[i+1], x[1], max.distance=0.25)))
  ex <- embed(x, 2)
  c(x[1], ifelse(same, ex[, 2], ex[, 1]))
}
df$B <- f(df$A)
df

     A    B
1  xxx  xxx
2  xxx  xxx
3 xxx1  xxx
4 xx1x xxx1
5 yyyy yyyy
6 gggg gggg
dat <- data.frame(A=c('xxx','xxx','xxx1','xx1x','yyyy','gggg'))
dat$B <- rep(NA,nrow(dat))

tmp <- strsplit(as.character(dat$A),"")
dat$B[1] <- dat$A[1]
for (i in 2:length(tmp)){
    n <- min(length(tmp[[i]]),length(tmp[[i-1]]))
    x <- sum(tmp[[i]][1:n] == tmp[[i-1]][1:n]) / length(tmp[[i]])
    if (x >= 0.75){
        dat$B[i] <- paste(tmp[[i-1]],collapse="")
    }
    else{ dat$B[i] <- paste(tmp[[i]],collapse="")}
}