Fórmula para encontrar correspondências "quase perfeitas" [duplicadas]

7

Eu tenho uma lista de + -8000 itens, que é o resultado depois de aplicar várias técnicas para remover duplicatas (a lista começou em mais de 10.000 itens).

Agora tenho o seguinte problema -

Exemplo 1. Jack Daniel 2. Jack Daniels 3. Jack Daniel's

Evidentemente, todos os itens acima se referem a um item, mas eles ainda são tecnicamente únicos. Tentei puxar as primeiras 4 letras e verificar se havia correspondências, mas havia + -4000 e a maioria delas eram falsos positivos, ou seja,

  1. Jack Dxxx
  2. Jack Bxxx

Ambos puxariam Jack, mas não seria uma duplicata válida.

Alguma opinião?

    
por brandon 01.11.2013 / 19:59

2 respostas

3

Com base no comentário da Zoredache, aqui está meu exemplo de pasta de trabalho usando o VBA e a Distância Levenshtein para encontrar strings semelhantes dentro de uma lista grande. É baseado nas respostas @smirkingman e @ Apostolos55 em stackoverflow .

The Levenshtein distance between two words is the minimum number of single-character edits (insertion, deletion, substitution) required to change one word into the other

Eu implementei duas versões diferentes. Por favor, verifique qual função é mais rápida para o seu caso com 8000 valores. Se você estiver curioso, veja o código completo do VBA em Github . Aumente o limite na linha const treshold = 1 se você quiser resultados com mais de 1 edição necessária para obter uma correspondência em algum lugar.

  • Sintaxedafórmula:=LevenshteinCompare(<cell_to_check>,<range_to_search_in>)
    Exemplo:=LevenshteinCompare(A2;A$2:A$12)(observeointervalofixo)
  • Sintaxedesaída:<number_of_required_edits>-[<match_address>]<match_value>
PrivateFunctionLevenshtein(S1AsString,S2AsString)DimiAsInteger,jAsIntegerDiml1AsInteger,l2AsIntegerDimd()AsIntegerDimmin1AsInteger,min2AsIntegerl1=Len(S1)l2=Len(S2)ReDimd(l1,l2)Fori=0Tol1d(i,0)=iNextForj=0Tol2d(0,j)=jNextFori=1Tol1Forj=1Tol2IfMid(S1,i,1)=Mid(S2,j,1)Thend(i,j)=d(i-1,j-1)Elsemin1=d(i-1,j)+1min2=d(i,j-1)+1Ifmin2<min1Thenmin1=min2EndIfmin2=d(i-1,j-1)+1Ifmin2<min1Thenmin1=min2EndIfd(i,j)=min1EndIfNextNextLevenshtein=d(l1,l2)EndFunctionPublicFunctionLevenshteinCompare(S1AsRange,wordrangeAsRange)Consttreshold=1ForEachS2InApplication.Intersect(wordrange,wordrange.Parent.UsedRange)oldRes=newResnewRes=Levenshtein(S1.Value,S2.Value)IfoldRes<newResAndoldRes<>"" Or S1.Address = S2.Address Then
        newRes = oldRes
        newS2row = oldS2row
    Else
        oldS2 = S2
        oldS2row = S2.Address(0, 0)
    End If
    newS2 = oldS2
Next

If newRes <= treshold Then
    LevenshteinCompare = newRes & " - [" & newS2row & "]  " & newS2
Else
    LevenshteinCompare = ""
End If
End Function

Isso foi divertido ☜ (゚ ヮ ゚ ☜)

    
por 02.11.2013 / 02:20
0

Use = len e se a diferença for menor que 2, marque como possível

e algo como = mid (Valor, (len_Value - 7), 4) marcá-lo como possilbe dupe.

Combinado com o que você já tem, você deve ter um conjunto muito mais viável para trabalhar.

Editar

Fórmulas como esta, Observe que "Jack Daniel" < > "Jack Berries" no G2. mas parece uma possível correspondência em qualquer outro lugar. Você precisaria modificar um pouco para atender às suas necessidades específicas, mas deveria chegar a um número gerenciável.

C1 = SE (ESQUERDA (A1,4) = ESQUERDA (B1,4), "T", "F")

D1 = IF (LEN (A1) - LEN (B1) < = 2, "T", "F")

E1 = LEN (A1)

F1 = LEN (B1)

G1 = IF (MID (A1, (E1 - 7), 4) = MID (B1, (E1 - 7), 4), "T", "F")

    
por 01.11.2013 / 20:19