Как нормализовать имена

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

Company    Customers
AAAB       1,000
AAAB Inc.  900
The AAAB Inc.  20
AAAB the INC   10

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


person Alexis_Kiwis    schedule 17.10.2013    source источник
comment
связанные: stackoverflow.com/q/13636848/1240268, я думаю, что лучше всего начать с фактического списка компаний и попытайтесь разработать хорошую метрику/функцию для похожих имен.   -  person Andy Hayden    schedule 18.10.2013
comment
Я проверил эту ссылку и увидел большое применение для get_close_matches. Однако у меня были некоторые проблемы с поиском правильного исполнения. Я использовал #Spend['Manufacturer'] = Spend['Manufacturer'].map(lambda x: difflib.get_close_matches(x,Spend['SKU/Catalog #'],5)) ): manuf = [] for i in n: Spend['Производитель'].map(lambda i: difflib.get_close_matches(i,Spend['Производитель'],5)) return manuf spend('Производитель') TypeError: object типа 'float' не имеет len(). Я пытаюсь исправить эту ошибку, но не знаю, как это сделать.   -  person Alexis_Kiwis    schedule 18.10.2013
comment
сходство триграмм творит чудеса. Я обычно использую такой инструмент, как cleanco, а затем использую сходство триграмм в PostgreSQL или сопоставление подобия в Snowflake [во многих случаях оба будут работать потенциально быстрее, чем Python из-за стоимости извлечения и хранения данных, особенно Snowflake].   -  person Andrew Scott Evans    schedule 27.07.2021


Ответы (3)


Я помню, как читал этот блог о библиотека fuzzywuzzy (смотрим в еще вопрос), который может сделать это:

pip install fuzzywuzzy

Вы можете использовать его функцию partial_ratio для «нечеткого сопоставления» строк:

In [11]: from fuzzywuzzy.fuzz import partial_ratio

In [12]: partial_ratio('AAAB', 'the AAAB inc.')
Out[12]: 100

Который кажется уверенным в том, что это хороший матч!

In [13]: partial_ratio('AAAB', 'AAPL')
Out[13]: 50

In [14]: partial_ratio('AAAB', 'Google')
Out[14]: 0

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

In [15]: co_list = ['AAAB', 'AAPL', 'GOOG']

In [16]: df.Company.apply(lambda mistyped_co: max(co_list, 
                                                  key=lambda co: partial_ratio(mistyped_co, co)))
Out[16]: 
0    AAAB
1    AAAB
2    AAAB
3    AAAB
Name: Company, dtype: object

Я сильно подозреваю, что в scikit Learn или библиотеке numpy есть что-то, что делает это более эффективно на больших наборах данных... но это должно помочь.

Если у вас нет списка компаний, вам, вероятно, придется сделать что-то более умное...

person Andy Hayden    schedule 17.10.2013
comment
Эй, это потрясающе. Спасибо, что познакомили меня с нечеткой статьей. Я возьму некоторое время, чтобы проверить это и посмотреть, как я могу применить его. - person Alexis_Kiwis; 18.10.2013
comment
@user2832824, пожалуйста, проголосуйте, если это было полезно, а также примите решение, если оно ответило на ваш вопрос meta.stackexchange.com/a/5235/184179 - person Andy Hayden; 15.11.2013

splitCompaniesSet = map( lambda cmpnyName : 
    set( map( lambda name : name.split(" "), cmpnyName ) ), dataFrame['Company'] )

Я думаю, это правильно.

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

Затем перейдите к следующему Company, который дал пустой набор при пересечении с первым названием компании. Затем сделайте это для следующих Company, которые были пустыми для первых двух, которые вы пробовали, и так далее.

Хотя, возможно, есть более эффективный способ.

person Matthew Turner    schedule 17.10.2013
comment
Интересно, попробую. Я искал нормализацию в модуле unicodedata. Однако я не был уверен, что это применимо к данной ситуации. Я также обнаружил в zope.component import getUtility из plone.i18n.normalizer.interfaces import IIDNormalizer от разработчика. plone.org/misc/normalizing_ids.html, и я не знаю, как мне импортировать эти модули. Казалось, мне нужно было загрузить что-то еще. - person Alexis_Kiwis; 18.10.2013
comment
Да я вижу. Вместо того, чтобы возиться с множествами, вы могли бы использовать fuzzywuzzy.fuzz.partial_ratio и установить для всех тех, где partial_ratio=100, одно и то же имя. Это устранит необходимость иметь список компаний, как предложил Энди. - person Matthew Turner; 18.10.2013

Используйте 1_

Попробуйте следующий код: -

from cleanco import prepare_terms, basename
business_name = "The AAAB Inc."
terms = prepare_terms()
basename(business_name, terms, prefix=False, middle=False, suffix=True)

Ожидаемый результат: -

The AAAB
person tuhinsharma121    schedule 17.03.2021