Распределение значений по группам

В примере ниже использованы условные данные. Мой рабочий датасет состоит из 250к позиций, а список продуктов из 3к позиций.

df = pd.DataFrame(['ap','apple','cтекло apple','a','ap','brother', 'br', 'brother 2'])
df.columns = ['nom']

product_list = ['ap','apple','br','brother', 'br s']

def categorize(row):
    for i in product_list:
        if i in row:
            return i

df['product'] = df['nom'].apply(categorize)
print(df)

Проблема заключается в том, что позиция 'стекло apple' попадает в категорию 'ap' вместо 'apple'. Как решить эту проблему?


Ответы (2 шт):

Автор решения: CrazyElf

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

product_list = sorted(['ap','apple','br','brother', 'br s'], key=len, reverse=True)
# product_list = ['brother', 'apple', 'br s', 'ap', 'br']

На выходе:

            nom  product
0            ap       ap
1         apple    apple
2  cтекло apple    apple
3             a     None
4            ap       ap
5       brother  brother
6            br       br
7     brother 2  brother
→ Ссылка
Автор решения: Алексей Р

В дополнение к ответу @CrazyElf предложу иной способ сопоставления массивов - через regex. Можно (предварительно отсортировав, как указал @CrazyElf), а также экранировав возможные специальные символы, создать паттерн вида (слово1|слово2|слово3) и затем применить к серии метод .str.extract, который и вытащит совпадающие подстроки - так мы уходим от необходимости применять циклы в явном виде. В примере ниже паттерн сделан из 5000 позиций, отрабатывает нормально:

import re
import pandas as pd

df = pd.DataFrame(['ap', 'apple', 'cтекло apple', 'a', 'ap', 'brother', 'br', 'brother 2'], columns=['nom'])
product_list = '(' + '|'.join(map(re.escape, sorted(['ap', 'apple', 'br', 'brother', 'br s'] * 1000, key=len, reverse=True))) + ')'
df['product'] = df['nom'].str.extract(product_list)
print(df)
            nom  product
0            ap       ap
1         apple    apple
2  cтекло apple    apple
3             a      NaN
4            ap       ap
5       brother  brother
6            br       br
7     brother 2  brother

Скорость не мерял.

→ Ссылка