2011-06-29 112 views
4

我DF有以下条目:R:搜索字符串相似,有条件的符号返回

A 
xxx 
xxx 
xxx1 
xx1x 
yyyy 
gggg 

我想基于符号添加到基于A列的相似性我DF的B柱,以下条件。

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

  • A列已经排序。因此, 需要检查上述 以上的ONE的相似性。

  • 如果上一个类似,符号 会从上一个专栏B.

  • 如果上一个不一样,在 符号将来自同一行的A列中拷贝复制

例如,第1行和第2行是相同的。它们的符号与列A相同。第3行是(4个字母中的3个字母具有相同的字母并且具有相同的序列)与第1行和第2行相似75%。它的列B中的sybmol将从上面的xxx复制而来。由于xx1x(row4)只有4个字母中的2个类似于row3,所以它将使用自己的符号,即xx1x。由于YYYY和GGGG是完全不同的,他们将继续自己的sybmol在A列

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

A  B 
xxx xxx 
xxx xxx 
xxx1 xxx 
xx1x xx1x 
yyyy yyyy 
gggg gggg 

我想出通过猜测此相似%(其如果有正式的字符串相似性搜索方法,则不需要使用),如果在R中有任何正式的字符串相似性检查方法,那么使用它可能会很好。

你能介意指导如何有效地添加这个符号列与R吗?

回答

6

设置数据:

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]))) 

结果:

 A  B  
[1,] "xxx" "xxx" 
[2,] "xxx" "xxx" 
[3,] "xxx1" "xxx" 
[4,] "xx1x" "xxx1" 
[5,] "yyyy" "yyyy" 
[6,] "gggg" "gggg" 

为什么它的工作?

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

首先,agrep提供了测试多么相似字符串,使用Levenshtein edit distance,有效计数,将一个字符串转换到另一个需要个性变化的数量。参数max.distance=0.25意味着25%的模式字符串允许不同。

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

agrep("xxx", x, max.distance=0.25) 
[1] 1 2 3 4 

其次,embed提供的测试滞后变量的有用方法。例如,embed(x, 2) turns 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 
+0

等等,OP没有要B下的第四个条目是'xx1x'吗? – joran

+0

是的,他做到了,但他也承认他猜到了这个价值。 'agrep'使用正式的变化意义定义,并且默认配置为将所有的修改,删除和插入计数为一次。因此在这个例子中有两个变化。这可以在'agrep'的参数中进行一定程度的配置。有关详细信息,请参阅'?agrep'。 – Andrie

+0

啊,我明白了。谢谢! – joran

0

这里的一个更“基本”溶液(编辑,以解决一些问题在评论中提出):

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="")} 
} 
+0

谢谢。我可能误解了你的代码的使用。你能介意教我如何解决这个问题吗? – user2718

+0

> dat < - data.frame(A = c('xxx','xxx','xxx1','xx1x','yyyy','gggg')) > dat $ B < - rep(NA,nrow (dat)) > > tmp < - strsplit(dat $ A,“”) strsplit错误(dat $ A,“”):非字符参数 > dat $ B [1] < - dat $ A [1] > for(i in 2:length(tmp)){ + x < - sum(tmp [[i]] == tmp [[i-1]])/ length(tmp [[i]] ) +}其他{dat $ B [i] < - paste(tmp [ < - paste(tmp [[i]],collapse =“”)} +} 错误:找不到对象'tmp' – user2718

+0

我相信问题是我配置了R来保留字符向量作为charac在创建数据框时创建;默认是强制他们的因素。 'strsplit'需要一个字符向量,而不是一个因素。如果你使用'strsplit(as.character(dat $ A),“”)''它应该可以工作。从tmp [[i]] == tmp [[i-1]]比较中会有警告(但没关系),因为它们有时长度不同。 – joran

相关问题