Выясните, является ли название компании очень похожим на другое - Python - PullRequest
27 голосов
/ 19 июня 2011

Я работаю с большой базой данных предприятий.

Я хотел бы иметь возможность сравнить два названия компаний по сходству, чтобы увидеть, могут ли они быть дубликатами.

Нижесписок бизнес-названий, которые должны проверяться как имеющие высокую вероятность дублирования, каков хороший способ это сделать?

George Washington Middle Schl
George Washington School

Santa Fe East Inc
Santa Fe East

Chop't Creative Salad Co
Chop't Creative Salad Company

Manny and Olga's Pizza
Manny's & Olga's Pizza

Ray's Hell Burger Too
Ray's Hell Burgers

El Sol
El Sol de America

Olney Theatre Center for the Arts
Olney Theatre

21 M Lounge
21M Lounge

Holiday Inn Hotel Washington
Holiday Inn Washington-Georgetown

Residence Inn Washington,DC/Dupont Circle
Residence Inn Marriott Dupont Circle

Jimmy John's Gourmet Sandwiches
Jimmy John's

Omni Shoreham Hotel at Washington D.C.
Omni Shoreham Hotel

Ответы [ 8 ]

39 голосов
/ 19 июня 2011

Недавно я выполнил аналогичную задачу, хотя сопоставлял новые данные с существующими именами в базе данных, а не искал дубликаты в одном наборе.Сопоставление имен - это на самом деле хорошо изученная задача, с множеством факторов, выходящих за рамки соответствия общих строк.

Во-первых, я бы порекомендовал взглянуть на бумагу, Как играть в «игру имен»: патентный поиск, сравнивающий различные эвристики Раффо и Луильери.Опубликованная версия - здесь , а PDF свободно доступен здесь .Авторы дают хорошее резюме, сравнивая ряд различных подходящих стратегий.Они рассматривают три этапа, которые они называют анализом, сопоставлением и фильтрацией.

Анализ состоит из применения различных методов очистки.Некоторые примеры:

  • Стандартизация букв (например, все строчные буквы)
  • Стандартизация знаков препинания (например, запятые должны сопровождаться пробелами)
  • Стандартизация пробелов (например, преобразованиевсе пробелы в пробелах)
  • Стандартизация акцентированных и специальных символов (например, преобразование акцентированных букв в эквиваленты ASCII)
  • Стандартизация терминов правового контроля (например, преобразование "Co." в "Company"")

В моем случае я сложил все буквы в нижний регистр, заменил все знаки пунктуации пробелами, заменил символы ударения на символы без акцента, удалил все другие специальные символы и удалил юридические термины управления с самого начала иКонцы имен, следующих за списком.

Соответствие - это сравнение проанализированных имен.Это может быть простое сопоставление строк, расстояние редактирования, Soundex или Metaphone, сравнение наборов слов, составляющих имена, или сравнение наборов букв или n -грамм (буквенные последовательности длиной n).Подход n -грам на самом деле очень хорош для имен, поскольку он игнорирует порядок слов, что очень помогает в таких вещах, как «отдел примеров» или «отдел примеров».На самом деле, сравнение биграмм (2 грамма, пары символов) с использованием чего-то простого, например, Jaccard index , очень эффективно.В отличие от нескольких других предложений, расстояние Левенштейна является одним из худших подходов, когда дело доходит до сопоставления имен.

В моем случае, сопоставление было выполнено в два этапа, сначала со сравнениемпроанализировал имена на равенство, а затем с помощью индекса Жакара для наборов биграмм на оставшихся.Вместо того, чтобы фактически вычислять все значения индекса Жакара для всех пар имен, я сначала наложил ограничение на максимально возможное значение индекса Жакара для двух наборов данного размера, и вычислял индекс Жакара только в том случае, если эта верхняя граница была достаточно высокой, чтобыпотенциально быть полезным.Большинство пар имен были все еще достаточно различны, чтобы не совпадать, но это значительно сократило количество сравнений.

Фильтрация - это использование вспомогательных данных для отклонения ложных срабатываний на этапах анализа и сопоставления.Простая версия заключается в том, чтобы увидеть, соответствуют ли совпадающие названия предприятиям в разных городах и, следовательно, различным предприятиям.Этот пример может быть применен перед сопоставлением, как своего рода предварительная фильтрация.Более сложные или трудоемкие проверки могут быть применены впоследствии.

Я не делал много фильтрации.Я проверил страны для фирм, чтобы видеть, были ли они одинаковыми, и это было этим.На самом деле в данных было не так много возможностей, некоторые ограничения по времени исключали какой-либо расширенный поиск дополнительных данных для усиления фильтрации, и в любом случае планировалась ручная проверка.

9 голосов
/ 09 ноября 2016

Я хотел бы добавить несколько примеров к превосходному принятому ответу.Протестировано в Python 2.7.

Синтаксический анализ

Давайте использовать это нечетное имя в качестве примера.

name = "THE |  big,- Pharma: LLC"  # example of a company name

Мы можем начать с удаления терминов правового контроля (здесь LLC).Для этого есть потрясающая cleanco библиотека Python, которая делает именно это:

from cleanco import cleanco
name = cleanco(name).clean_name()  # 'THE | big,- Pharma'

Удаляет все знаки пунктуации:

name = name.translate(None, string.punctuation)  # 'THE  big Pharma'

(для строк Unicode,вместо этого работает следующий код ( source , regex ):

import regex
name = regex.sub(ur"[[:punct:]]+", "", name)  # u'THE  big Pharma'

Разделить имя на токены, используя NLTK :

import nltk
tokens = nltk.word_tokenize(name)  # ['THE', 'big', 'Pharma']

Строчные все токены:

tokens = [t.lower() for t in tokens]  # ['the', 'big', 'pharma']

Удалите стоп-слова. Обратите внимание, что это может привести к проблемам с такими компаниями, как On Mars будет некорректно соответствовать Mars, потому что On - стоп-слово.

from nltk.corpus import stopwords
tokens = [t for t in tokens if t not in stopwords.words('english')]  # ['big', 'pharma']

Я не рассматриваю здесь акцентированные и специальные символы (улучшения приветствуются).

Соответствует

Теперь, когда мы сопоставили все названия компаний с токенами,мы хотим найти совпадающие пары. Возможно, сходство Жакара (или Яро-Винклера) лучше, чем Левенштейна, для этой задачи, но все еще недостаточно хорошо. Причина в том, что он не учитывает важность слов в названии.(как это делает TF-IDF). Такие распространенные слова, как «Компания«влияют на оценку так же, как слова, которые могут однозначно идентифицировать название компании.

Чтобы улучшить это, вы можете использовать трюк подобия имени, предложенный в этой потрясающей серии сообщений (не мое).Вот пример кода из него:

# token2frequency is just a word counter of all words in all names
# in the dataset
def sequence_uniqueness(seq, token2frequency):
    return sum(1/token2frequency(t)**0.5 for t in seq)

def name_similarity(a, b, token2frequency):
    a_tokens = set(a.split())
    b_tokens = set(b.split())
    a_uniq = sequence_uniqueness(a_tokens)
    b_uniq = sequence_uniqueness(b_tokens)
    return sequence_uniqueness(a.intersection(b))/(a_uniq * b_uniq) ** 0.5

Используя это, вы можете сопоставить имена с сходством, превышающим определенный порог.В качестве более сложного подхода вы также можете взять несколько баллов (скажем, этот балл уникальности, Джакарда и Яро-Винклера) и обучить двоичную модель классификации, используя некоторые помеченные данные, которые при заданном количестве баллов будут выводить, если пара кандидатовэто совпадение или нет.Подробнее об этом можно узнать из того же сообщения в блоге.

7 голосов
/ 09 января 2016

Существует отличная библиотека для поиска похожих / нечетких строк для python: fuzzywuzzy . Это хорошая библиотека-обертка после упомянутого измерения расстояния Левенштейна. Вот как можно проанализировать ваши имена:

#!/usr/bin/env python

from fuzzywuzzy import fuzz

names = [
    ("George Washington Middle Schl",
     "George Washington School"),

    ("Santa Fe East Inc",
     "Santa Fe East"),

    ("Chop't Creative Salad Co",
     "Chop't Creative Salad Company"),

    ("Manny and Olga's Pizza",
     "Manny's & Olga's Pizza"),

    ("Ray's Hell Burger Too",
    "Ray's Hell Burgers"),

    ("El Sol",
    "El Sol de America"),

    ("Olney Theatre Center for the Arts",
    "Olney Theatre"),

    ("21 M Lounge",
    "21M Lounge"),

    ("Holiday Inn Hotel Washington",
    "Holiday Inn Washington-Georgetown"),

    ("Residence Inn Washington,DC/Dupont Circle",
    "Residence Inn Marriott Dupont Circle"),

    ("Jimmy John's Gourmet Sandwiches",
    "Jimmy John's"),

    ("Omni Shoreham Hotel at Washington D.C.",
    "Omni Shoreham Hotel"),
]

if __name__ == '__main__':
    for pair in names:
        print "{:>3} :: {}".format(fuzz.partial_ratio(*pair), pair)

>>>  79 :: ('George Washington Middle Schl', 'George Washington School')
>>> 100 :: ('Santa Fe East Inc', 'Santa Fe East')
>>> 100 :: ("Chop't Creative Salad Co", "Chop't Creative Salad Company")
>>>  86 :: ("Manny and Olga's Pizza", "Manny's & Olga's Pizza")
>>>  94 :: ("Ray's Hell Burger Too", "Ray's Hell Burgers")
>>> 100 :: ('El Sol', 'El Sol de America')
>>> 100 :: ('Olney Theatre Center for the Arts', 'Olney Theatre')
>>>  90 :: ('21 M Lounge', '21M Lounge')
>>>  79 :: ('Holiday Inn Hotel Washington', 'Holiday Inn Washington-Georgetown')
>>>  69 :: ('Residence Inn Washington,DC/Dupont Circle', 'Residence Inn Marriott Dupont Circle')
>>> 100 :: ("Jimmy John's Gourmet Sandwiches", "Jimmy John's")
>>> 100 :: ('Omni Shoreham Hotel at Washington D.C.', 'Omni Shoreham Hotel')

Другим способом решения таких проблем может быть Elasticsearch , который также поддерживает нечеткие поиски.

7 голосов
/ 19 июня 2011

Вы можете использовать расстояние Левенштейна, которое можно использовать для измерения разницы между двумя последовательностями (в основном это расстояние редактирования).

Расстояние Левенштейна в Python

def levenshtein_distance(a,b):
    n, m = len(a), len(b)
    if n > m:
        # Make sure n <= m, to use O(min(n,m)) space
        a,b = b,a
        n,m = m,n

    current = range(n+1)
    for i in range(1,m+1):
        previous, current = current, [i]+[0]*n
        for j in range(1,n+1):
            add, delete = previous[j]+1, current[j-1]+1
            change = previous[j-1]
            if a[j-1] != b[i-1]:
                change = change + 1
            current[j] = min(add, delete, change)

    return current[n]

if __name__=="__main__":
    from sys import argv
    print levenshtein_distance(argv[1],argv[2])
2 голосов
/ 19 июня 2011

Рассмотрите возможность использования библиотеки Diff-Match-Patch .Вас заинтересует процесс Diff - применение diff к вашему тексту может дать вам хорошее представление о различиях, а также их программное представление.

2 голосов
/ 19 июня 2011

Я искал "расстояние редактирования питона", и эта библиотека стала первым результатом: http://www.mindrot.org/projects/py-editdist/

Здесь находится еще одна библиотека Python, которая выполняет ту же работу: http://pypi.python.org/pypi/python-Levenshtein/

расстояние редактирования представляет объем работы, который вам необходимо выполнить для преобразования одной строки в другую, выполнив только простые - обычно символьные - операции редактирования. Каждая операция (подстановка, удаление, вставка; иногда транспонирование) имеет связанную стоимость, и минимальное расстояние редактирования между двумя строками является мерой того, насколько они различны.

В вашем конкретном случае вы можете упорядочить строки так, чтобы вы находили расстояние от более длинного до более короткого и меньше штрафовали за удаление символов (потому что я вижу, что во многих случаях одна из строк является почти подстрокой другой). Таким образом, удаление не должно быть оштрафовано много.

Вы также можете использовать этот пример кода: http://norvig.com/spell-correct.html

1 голос
/ 05 июля 2018

Алгоритмы, основанные на расстоянии Левенштейна, хороши (не идеальны), но их главный недостаток в том, что они очень медленны для каждого сравнения и касаются того факта, что вам придется сравнивать все возможные комбинации.

Другим способом решения проблемы было бы использование встраивания или пакета слов для преобразования названия каждой компании (после некоторой очистки и предварительной обработки) в вектор чисел. И после этого вы применяете неконтролируемый или контролируемый метод ОД в зависимости от того, что доступно.

1 голос
/ 19 июня 2011

То, что вы можете сделать, это разделить слова пробелами, запятыми и т. Д., А затем подсчитать количество слов, которые у него есть общего с другим именем, и добавить несколько слов, прежде чем они будут считаться «похожими».

Другой способ - сделать то же самое, но взять слова и склеить их для каждого символа. Затем для каждого слова вам нужно сравнить, если буквы найдены в одинаковом порядке (с обеих сторон) для х символов (или процентов), то вы можете сказать, что слово тоже похоже.

Пример: у вас есть площадь и площадь

Затем вы проверяете символами и обнаруживаете, что все квадраты в квадрате и в том же порядке, тогда это похожее слово.

...