2017-03-07 241 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()'。 –

相关问题