web-dev-qa-db-ja.com

Excelでの類似したテキスト文字列の比較

現在、2つの個別のデータソースの「名前」フィールドを調整しようとしています。完全には一致していませんが、一致していると見なされるほど近い名前がいくつかあります(以下の例)。自動マッチの数をどのように改善できるかについてのアイデアはありますか?私はすでに一致基準からミドルイニシャルを除外しています。

enter image description here

現在の一致式:

=IFERROR(IF(LEFT(SYSTEM A,IF(ISERROR(SEARCH(" ",SYSTEM A)),LEN(SYSTEM A),SEARCH(" ",SYSTEM A)-1))=LEFT(SYSTEM B,IF(ISERROR(SEARCH(" ",SYSTEM B)),LEN(SYSTEM B),SEARCH(" ",SYSTEM B)-1)),"",IF(LEFT(SYSTEM A,FIND(",",SYSTEM A))=LEFT(SYSTEM B,FIND(",",SYSTEM B)),"Last Name Match","RESEARCH")),"RESEARCH")
14

Microsoft Fuzzy Lookup Addin の使用を検討してください。

MSサイトから:

概観

Excel用Fuzzy LookupアドインはMicrosoft Researchによって開発され、Microsoft Excelでテキストデータのあいまい一致を実行します。 1つのテーブル内の重複するファジー行を識別したり、2つの異なるテーブル間で類似した行をファジー結合したりするために使用できます。マッチングは、スペルミス、略語、類義語、追加/欠落データなど、さまざまなエラーに対して堅牢です。たとえば、「Mr。 Andrew Hill」、「Hill、Andrew R.」 「アンディヒル」はすべて同じ基本エンティティを参照し、一致ごとに類似性スコアを返します。既定の構成は、製品名や顧客の住所など、さまざまなテキストデータに対して適切に機能しますが、特定のドメインまたは言語に合わせてカスタマイズすることもできます。

12
techturtle

私は this リスト(英語のセクションのみ)を使用して、一般的な短縮形を取り除くのに役立てます。

さらに、2つの文字列がどのくらい「近い」かを正確に伝える関数の使用を検討することもできます。次のコードは here からのもので、 smirkingman のおかげです。

Option Explicit
Public Function Levenshtein(s1 As String, s2 As String)

Dim i As Integer
Dim j As Integer
Dim l1 As Integer
Dim l2 As Integer
Dim d() As Integer
Dim min1 As Integer
Dim min2 As Integer

l1 = Len(s1)
l2 = Len(s2)
ReDim d(l1, l2)
For i = 0 To l1
    d(i, 0) = i
Next
For j = 0 To l2
    d(0, j) = j
Next
For i = 1 To l1
    For j = 1 To l2
        If Mid(s1, i, 1) = Mid(s2, j, 1) Then
            d(i, j) = d(i - 1, j - 1)
        Else
            min1 = d(i - 1, j) + 1
            min2 = d(i, j - 1) + 1
            If min2 < min1 Then
                min1 = min2
            End If
            min2 = d(i - 1, j - 1) + 1
            If min2 < min1 Then
                min1 = min2
            End If
            d(i, j) = min1
        End If
    Next
Next
Levenshtein = d(l1, l2)
End Function

これにより、1つの文字列に対して他の文字列に到達するために必要な挿入と削除の数がわかります。私はこの数を低く保つように努めます(姓は正確でなければなりません)。

6
soandos

使用できる(長い)式があります。これは、上記のものほど洗練されていません–フルネームではなく姓でのみ機能します–しかし、あなたはそれが役に立つかもしれません。

したがって、ヘッダー行があり、A2B2を比較したい場合は、これをその行の他のセル(たとえば、C2)に配置し、最後までコピーします。

= IF(A2 = B2、 "EXACT"、IF(SUBSTITUTE(A2、 "-"、 "")= SUBSTITUTE(B2、 "-"、 "")、 "ハイフン"、IF(LEN(A2)> LEN( B2)、IF(LEN(A2)> LEN(SUBSTITUTE(A2、B2、 ""))、 "文字列全体"、IF(MID(A2,1,1)= MID(B2,1,1)、1、 0)+ IF(MID(A2,2,1)= MID(B2,2,1)、1,0)+ IF(MID(A2,3,1)= MID(B2,3,1)、1、 0)+ IF(MID(A2、LEN(A2)、1)= MID(B2、LEN(B2)、1)、1,0)+ IF(MID(A2、LEN(A2)-1,1)= MID(B2、LEN(B2)-1,1)、1,0)+ IF(MID(A2、LEN(A2)-2,1)= MID(B2、LEN(B2)-2,1)、1 、0)& "°")、IF(LEN(B2)> LEN(SUBSTITUTE(B2、A2、 ""))、 "文字列全体"、IF(MID(A2,1,1)= MID(B2,1 、1)、1,0)+ IF(MID(A2,2,1)= MID(B2,2,1)、1,0)+ IF(MID(A2,3,1)= MID(B2,3 、1)、1,0)+ IF(MID(A2、LEN(A2)、1)= MID(B2、LEN(B2)、1)、1,0)+ IF(MID(A2、LEN(A2) -1,1)= MID(B2、LEN(B2)-1,1)、1,0)+ IF(MID(A2、LEN(A2)-2,1)= MID(B2、LEN(B2)- 2,1)、1,0)& "°"))))

これは戻ります:

  • [〜#〜] exact [〜#〜] –完全一致の場合
  • ハイフン –ダブルバレルの名前のペアであるが、ハイフンがあり、もう一方にスペースがある場合
  • 文字列全体 – 1つの姓のすべてが他の姓の一部である場合(たとえば、スミスがフレンチスミスになった場合)

その後、2つの比較ポイントの数に応じて、0°から6°の程度が得られます。 (つまり、6°のほうが優れています)。

少しラフで準備ができていると言いますが、うまくいけば、大体正しい球場にあなたを連れて行きます。

5
Coriel-11

似たようなものを探していました。以下のコードを見つけました。これがこの質問に来る次のユーザーに役立つことを願っています

アブラカダブラ/アブラカダブラの場合は91%、ハリウッドストリート/ホリデーストリートの場合は75%、フィレンツェ/フランスの場合は62%、ディズニーランドの場合は0を返します

私はそれがあなたが望んだものに十分近いと思います:)

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
2
Adarsh

このコードは、列aと列bをスキャンします。両方の列に類似性が見つかると、黄色で表示されます。カラーフィルターを使用して、最終的な値を取得できます。その部分をコードに追加していません。

Sub item_difference()

Range("A1").Select

last_row_all = Range("A65536").End(xlUp).Row
last_row_new = Range("B65536").End(xlUp).Row

Range("A1:B" & last_row_new).Select
With Selection.Interior
    .Pattern = xlSolid
    .PatternColorIndex = xlAutomatic
    .Color = 65535
    .TintAndShade = 0
    .PatternTintAndShade = 0
End With

For i = 1 To last_row_new
For j = 1 To last_row_all

If Range("A" & i).Value = Range("A" & j).Value Then

Range("A" & i & ":B" & i).Select
With Selection.Interior
    .Pattern = xlSolid
    .PatternColorIndex = xlAutomatic
    .ThemeColor = xlThemeColorDark1
    .TintAndShade = 0
  .PatternTintAndShade = 0
End With

End If
Next j
Next i
End Sub
1
Ashwith Ullal

類似性関数(pwrSIMILARITY)を使用して文字列を比較し、2つの一致率を取得できます。大文字と小文字を区別するかどうかを指定できます。ニーズに「十分に近い」一致の割合を決定する必要があります。

http://officepowerups.com/help-support/Excel-function-reference/Excel-text-analyzer/pwrsimilarity/ に参照ページがあります。

ただし、列Aのテキストと列Bのテキストを比較する場合には非常にうまく機能します。

1
Xander

私のソリューションは非常に異なる文字列を識別することを許可していませんが、部分一致(部分文字列の一致)に役立ちます。 「これは文字列です」と「文字列」は「一致する」という結果になります。

テーブルに検索する文字列の前後に「*」を追加するだけです。

通常の式:

  • vlookup(A1、B1:B10,1,0)
  • cerca.vert(A1; B1:B10; 1; 0)

なる

  • vlookup( "*"&A1& "*"、B1:B10; 1,0)
  • cerca.vert( "*"&A1& "*"; B1:B10; 1; 0)

「&」はconcatenate()の「短縮版」です

1
jumpjack