Если у вас нет золотого набора «правильных» названий торговцев, это звучит как проблема кластеризации.Это может быть решено с помощью умной функции расстояния (как Jaro-Winkler из ответа Jindrich) и простого алгоритма кластеризации (например, агломерационная кластеризация).
После группировки текстов вы можете найти наиболее представительный текст из каждого кластера и заменить им весь кластер.
import numpy as np
import re
import textdistance
# we will need scikit-learn>=0.21
from sklearn.cluster import AgglomerativeClustering
texts = [
'Carrefour supermarket', 'Carrefour hypermarket', 'Carrefour', 'carrefour', 'Carrfour downtown', 'Carrfor market',
'Lulu', 'Lulu Hyper', 'Lulu dxb', 'lulu airport',
'k.m trading', 'KM Trading', 'KM trade', 'K.M. Trading', 'KM.Trading'
]
def normalize(text):
""" Keep only lower-cased text and numbers"""
return re.sub('[^a-z0-9]+', ' ', text.lower())
def group_texts(texts, threshold=0.4):
""" Replace each text with the representative of its cluster"""
normalized_texts = np.array([normalize(text) for text in texts])
distances = 1 - np.array([
[textdistance.jaro_winkler(one, another) for one in normalized_texts]
for another in normalized_texts
])
clustering = AgglomerativeClustering(
distance_threshold=threshold, # this parameter needs to be tuned carefully
affinity="precomputed", linkage="complete", n_clusters=None
).fit(distances)
centers = dict()
for cluster_id in set(clustering.labels_):
index = clustering.labels_ == cluster_id
centrality = distances[:, index][index].sum(axis=1)
centers[cluster_id] = normalized_texts[index][centrality.argmin()]
return [centers[i] for i in clustering.labels_]
print(group_texts(texts))
Приведенный выше код напечатает свой вывод как
['carrefour', 'carrefour', 'carrefour', 'carrefour', 'carrefour', 'carrefour',
'lulu', 'lulu', 'lulu', 'lulu',
'km trading', 'km trading', 'km trading', 'km trading', 'km trading']
В качестве базовой линии эта функция будет работать.Возможно, вы захотите улучшить его, изменив функцию расстояния, чтобы она более точно отражала ваш домен.Например:
- учитывает синонимы: супермаркет = гипермаркет = рынок
- лемматизировать слова (так что торговля = торговля)
- придают меньший весважные слова (IDF?)
К сожалению, большинство таких настроек будут относиться к конкретному домену, поэтому вам придется настроить их на свой собственный набор данных.