2011-06-29 113 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

相關問題