2017-03-07 282 views
0

可以說我有9行記錄。每3行具有相同的值。例如:在excel中查找行值之間的文本相似性

Mike
Mike
Mike
John
John
John
Ryan
Ryan
Ryan

有沒有一種方法可以搜索這些記錄的相似之處?例如,拼寫錯誤,附加字符,缺少字符等。因此,例如,正確的版本是Mike,但列表中可能有一條記錄,其值爲Mke,這是不正確的(拼寫錯誤)。我怎樣才能找到它並用正確的替換它?

上面的例子顯然簡化了。我其實有100萬行。現在要實現元素的「分組」,我只是按字母順序對它們進行排序。

回答

0

我面對完全一樣的問題!通過一些搜索,我可以獲得並修改以下VBA代碼,該代碼將啓用名爲=Similarity()的函數。根據兩個輸入單元格的相似性,此函數將輸出一個從0到1的數字。

  • 我如何使用它:

我按字母順序排序我的專欄的信息和應用的公式。然後我創建了一個Conditional Formatting Rule以突出顯示具有高相似性的那些(即:至少65%)。然後我搜索每個突出顯示的事件並手動修復我的記錄。

  • 用法:

    =相似度(小區1,小區2)

OB的。:相似度指示器從0到1變爲(0%至100%)

  • 實施例:

enter image description here

  • 要使用它,必須:

    1. 打開VBE(ALT + F11)
    2. 插入模塊
    3. 以下代碼粘貼到模塊窗口

enter image description here

代碼:

Public Function Similarity(ByVal String1 As String, _ 
    ByVal String2 As String, _ 
    Optional ByRef RetMatch As String, _ 
    Optional min_match = 1) As Single 

Dim b1() As Byte, b2() As Byte 
Dim lngLen1 As Long, lngLen2 As Long 
Dim lngResult As Long 

If UCase(String1) = UCase(String2) Then 
    Similarity = 1 
Else: 
    lngLen1 = Len(String1) 
    lngLen2 = Len(String2) 
    If (lngLen1 = 0) Or (lngLen2 = 0) Then 
     Similarity = 0 
    Else: 
     b1() = StrConv(UCase(String1), vbFromUnicode) 
     b2() = StrConv(UCase(String2), vbFromUnicode) 
     lngResult = Similarity_sub(0, lngLen1 - 1, _ 
     0, lngLen2 - 1, _ 
     b1, b2, _ 
     String1, _ 
     RetMatch, _ 
     min_match) 
     Erase b1 
     Erase b2 
     If lngLen1 >= lngLen2 Then 
      Similarity = lngResult/lngLen1 
     Else 
      Similarity = lngResult/lngLen2 
     End If 
    End If 
End If 

End Function 

Private Function Similarity_sub(ByVal start1 As Long, ByVal end1 As Long, _ 
           ByVal start2 As Long, ByVal end2 As Long, _ 
           ByRef b1() As Byte, ByRef b2() As Byte, _ 
           ByVal FirstString As String, _ 
           ByRef RetMatch As String, _ 
           ByVal min_match As Long, _ 
           Optional recur_level As Integer = 0) As Long 
'* CALLED BY: Similarity *(RECURSIVE) 

Dim lngCurr1 As Long, lngCurr2 As Long 
Dim lngMatchAt1 As Long, lngMatchAt2 As Long 
Dim I As Long 
Dim lngLongestMatch As Long, lngLocalLongestMatch As Long 
Dim strRetMatch1 As String, strRetMatch2 As String 

If (start1 > end1) Or (start1 < 0) Or (end1 - start1 + 1 < min_match) _ 
Or (start2 > end2) Or (start2 < 0) Or (end2 - start2 + 1 < min_match) Then 
    Exit Function '(exit if start/end is out of string, or length is too short) 
End If 

For lngCurr1 = start1 To end1 
    For lngCurr2 = start2 To end2 
     I = 0 
     Do Until b1(lngCurr1 + I) <> b2(lngCurr2 + I) 
      I = I + 1 
      If I > lngLongestMatch Then 
       lngMatchAt1 = lngCurr1 
       lngMatchAt2 = lngCurr2 
       lngLongestMatch = I 
      End If 
      If (lngCurr1 + I) > end1 Or (lngCurr2 + I) > end2 Then Exit Do 
     Loop 
    Next lngCurr2 
Next lngCurr1 

If lngLongestMatch < min_match Then Exit Function 

lngLocalLongestMatch = lngLongestMatch 
RetMatch = "" 

lngLongestMatch = lngLongestMatch _ 
+ Similarity_sub(start1, lngMatchAt1 - 1, _ 
start2, lngMatchAt2 - 1, _ 
b1, b2, _ 
FirstString, _ 
strRetMatch1, _ 
min_match, _ 
recur_level + 1) 
If strRetMatch1 <> "" Then 
    RetMatch = RetMatch & strRetMatch1 & "*" 
Else 
    RetMatch = RetMatch & IIf(recur_level = 0 _ 
    And lngLocalLongestMatch > 0 _ 
    And (lngMatchAt1 > 1 Or lngMatchAt2 > 1) _ 
    , "*", "") 
End If 


RetMatch = RetMatch & Mid$(FirstString, lngMatchAt1 + 1, lngLocalLongestMatch) 


lngLongestMatch = lngLongestMatch _ 
+ Similarity_sub(lngMatchAt1 + lngLocalLongestMatch, end1, _ 
lngMatchAt2 + lngLocalLongestMatch, end2, _ 
b1, b2, _ 
FirstString, _ 
strRetMatch2, _ 
min_match, _ 
recur_level + 1) 

If strRetMatch2 <> "" Then 
    RetMatch = RetMatch & "*" & strRetMatch2 
Else 
    RetMatch = RetMatch & IIf(recur_level = 0 _ 
    And lngLocalLongestMatch > 0 _ 
    And ((lngMatchAt1 + lngLocalLongestMatch < end1) _ 
    Or (lngMatchAt2 + lngLocalLongestMatch < end2)) _ 
    , "*", "") 
End If 

Similarity_sub = lngLongestMatch 

End Function 
  • 根據您的數據集輸出:

enter image description here

+0

謝謝你的回答,它工作正常。現在問題變成了我擁有〜11k「正確」的價值。所以手工工作需要很多時間。你有什麼想法,我會如何自動化這個東西? –

+0

呃......我知道一些關於詞幹化和詞性化的問題,但是很難將他們的算法應用於名稱,因爲名字不尊重格式規則。我的意思是,Myike,Myke和Miyke都是可以接受的(並且是社交的),那麼當你的程序發現它時,你的程序如何知道哪個值是「正確的」,例如「Myke」?它應該取代「邁克」還是什麼?也許您可以從11k行中刪除具有「高度相似性」的重複項,然後您可以使用「名稱詞典」,「IF()」,「SUBSTITUTE( )'和'OR()'。 –

相關問題