Как бы я сгруппировал набор похожих названий продуктов?

#python

#python

Вопрос:

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

 List = ['CocaCola','CocaCola 3 Oz','Twix','Twix Caramel','Foldgers 3 Oz','Foldgers 10 Oz','Haagen Dazs Caramel','Black Forest Ham','Black Label Whiskey',...] 
  

Я хотел бы написать функцию, которая группировала бы похожие названия продуктов, чтобы возвращать список:

 NewList = ['CocaCola','Twix','Foldgers','Haagen Dazs Caramel','Black Forest Ham','Black Label Whiskey',...]
  

Я думал о сопоставлении подстрок, но это не сработало бы, поскольку «CocaCola 3 Oz» и «Foldgers 3 Oz» оба отображались бы на «3 унции».

Я также подумал только о первой подстроке в каждом названии продукта:

  NewList = []
 for w in List: 
     ws = w.split(' ')
     NewList.append(ws[0]) 
  

Но это сопоставило бы ‘ветчину из Шварцвальда’ и ‘Виски Black Label’ с ‘Черным’.

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


Для уточнения на основе комментариев Брусуэйна: Я получаю список из Pandas df (не знаю, почему это актуально?). ‘CocaCola’ и ‘Pepsi’ будут сопоставлены с разными группами ‘CocaCola’ и ‘Pepsi’. ‘Ветчина из Шварцвальда’ и ‘Ветчина Оскара Мейера’ также были бы отнесены к разным группам, ‘CocaCola’ и ‘CocaCola Light’ были бы отнесены к одной и той же группе ‘CocaCola’. В основном я ищу группировку на основе названий брендов, а не категорий продуктов. Это то, что определяет сходство.

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

Я подумал, что beautifulsoup поможет, потому что это библиотека для обработки текста.

Комментарии:

1. Что определяет, похожи ли продукты? Twix и Twix Caramel более очевидно, но хотели бы вы сгруппировать CocaCola и Pepsi вместе? Как насчет Black Forest Ham и Oscar Meyer Ham ? Можете ли вы показать ожидаемый результат для включенных вами примеров? Что beautifulsoup имеет к этому отношение? Вы получаете этот список откуда-нибудь из Интернета или из XML-документа?

2. Что касается вашей правки: как бы вы идентифицировали название бренда в строке?

3. @KlausD. в этом суть моего вопроса. Я не знаю всех названий брендов заранее, или я бы использовал какую-то таблицу поиска.

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

5. (Мои извинения, не понял, что второй список был ожидаемым результатом.)

Ответ №1:

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

 a = ['CocaCola','CocaCola 3 Oz','Twix','Twix Caramel','Foldgers 3 Oz','Foldgers 10 Oz','Haagen Dazs Caramel','Black Forest Ham','Black Label Whiskey']

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.cluster import KMeans
cv=CountVectorizer()
vect=cv.fit_transform(a)
km=KMeans(n_clusters=6)
km.fit_predict(vect)
  

ВЫХОДНОЙ СИГНАЛ:

 array([0, 0, 1, 1, 2, 2, 4, 3, 5], dtype=int32)
  

Это говорит нам о том, что:

Кластер 0: «Кокакола», «КокаКола 3 унции»

Группа 1: «Твикс», «Твикс Карамельный»

Группа 2: «Формочки 3 унции», «Формочки 10 унций»

Группа 3: «Карамель Haagen Dazs»

Кластер 4: «Ветчина из Шварцвальда»

Группа 5: «Виски Black Label»

Сначала вы векторизуете свои данные, т.е. преобразуете каждый элемент в вашем списке в одномерный массив чисел. Здесь я использую CountVectorizer (его легко понять и он служит этой цели), но доступны и другие векторизаторы. Каждая цифра в массиве 1D будет представлять слово, а значение этой цифры будет представлять количество раз, когда оно встречается в этом тексте. Эта ссылка поможет вам лучше понять CountVectorizer, он же алгоритм набора слов.

Опять же, существует множество алгоритмов кластеризации на выбор, и я выбрал кластеризацию KMeans по той же причине, что и раньше, — ее легко понять и реализовать.Это поможет вам понять кластеризацию KMeans.

Примечание: Вам нужно указать количество кластеров, которое вам требуется, как указано в km=KMeans(n_clusters=6) . Изменение значения здесь может изменить ваши результаты. Например,

Если km=KMeans(n_clusters=5) , то «Ветчина Шварцвальд» и «Виски Black Label» будут отнесены к одной категории в одном кластере.

Я надеюсь, что это поможет вам.

Ответ №2:

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

 products = ['CocaCola','CocaCola 3 Oz','Twix','Twix Caramel','Foldgers 3 Oz','Foldgers 10 Oz','Haagen Dazs Caramel','Black Forest Ham','Black Label Whiskey']
import re
products = list(set(re.findall("(.*?)[0-9]",name "0")[0].strip() for name in products))
print(products)

# ['Black Label Whiskey', 'CocaCola', 'Black Forest Ham', 'Twix Caramel', 'Twix', 'Haagen Dazs Caramel', 'Foldgers']