File size: 5,244 Bytes
d869f0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd53dcf
 
fdc26d9
 
 
 
d869f0d
 
 
 
 
 
 
 
 
 
 
fd53dcf
 
 
d869f0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def flatten(items, seqtypes=(list, tuple)):
    try:
        for i, x in enumerate(items):
            while isinstance(x, seqtypes):    
                items[i:i+1] = x
                x = items[i]
    except IndexError:
        pass
    return items

aliases = [
  #('canonical name', ['aliases', ...])
  ('почта россия', ['почта', 'почта рф', 'пр', 'gh']),
  ('почта россия трекинг', ['пр трекинг', 'почта трекинг', 'пр трэкинг', 'почта трэкинг']),
  ('реестр почта', ['реестр пр', 'реестр почта россии']),
  ('реестр пэк', []),
  ('реквизиты', []),
  ('пешкарики', []),
  ('импорт лидов директ', []),
  ('яндекс доставка экспресс', ['яндекс доставка express', 'яд экспресс', 'ядоставка экспресс']),
  ('яндекс доставка ndd', ['яд ндд', 'я доставка ндд', 'ядоставка ндд', 'модуль ндд']),
  ('яндекс метрика', ['яндекс метрика импорт']),
  ('альфабанк', ['альфа банк', 'alfabank', 'альфа']),
  ('импорт лидов facebook', ['импорт лидов fb', 'загрузка лидов fb', 'лиды фейсбук', 'импорт лидов фб', 'fb lead']),
  ('маркетинговые расходы', ['расходы', 'загрузка расходов']),
  ('cloudpayments', ['клауд', 'клаудпеймент', 'клаудпейментс']),
  ('robokassa', ['робокасса', 'робокаса']),
  ('sipuni', ['сипуни', 'сипьюни']),
  ('mailchimp', ['майлчимп', 'мейлчим', 'мейлчимп']),
  ('unisender', ['юнисендер']),
  ('яндекс аудитории', ['экспорт аудитории', 'экспорт яндекс аудитории']),
  ('экспорт facebook', ['экспорт сегментов facebook', 'экспорт fb', 'экспорт фейсбук', 'экспорт аудиторий фб', 'fb экспорт']),
  ('экспорт вк', ['экспорт сегментов vkontakte', 'экспорт vk', 'экспорт контакте']),
  ('retailcrm', ['срм', 'ритейл', 'ритейл срм', 'ритейлсрм', 'retail crm', 'ритейлцрм', 'ритейл црм']),
  ('retailcrm services', [
    'retailcrmservices', 'ритейлцрм services', 'лк crm services', 'ритейлцрм сервисес',
    'ритейлсрм сервисес', 'ритейлцрм сервисе', 'ритейлцрмсервисес', 'ритейлсрмсервисес',
  ])
]

vocab_raw = flatten([[k] + keywords for k, keywords in aliases])

import string
import pymorphy3

morph = None
def normalize_word(word):
    if word == 'лид':
        return word
    if word in ['росии', 'росси']:
        return 'россия'

    global morph
    if morph is None:
        morph = pymorphy3.MorphAnalyzer()
    return morph.parse(word)[0].normal_form

def tokenize_sentence(text):
    # remove punctuation
    text = text.translate(str.maketrans(string.punctuation, ' ' * len(string.punctuation)))
    # tokenize
    return [normalize_word(word) for word in text.split()]
  
def normalize_sentence(text):
    return " ".join(tokenize_sentence(text))

def canonical_keywords(keywords):
    """
    replace keyword aliases with canonical keyword names
    """
    result = []
    for k in keywords:
        k = normalize_sentence(k)
        for canonical_name, alias_names in aliases:
            canonical_name = normalize_sentence(canonical_name)
            for a in alias_names:
                a = normalize_sentence(a)
                #print('a', a)
                if a == k:
                    result.append(canonical_name)
                    break
            else:
                continue
            break
        else:
            result.append(k)
    return result

def merge_keywords(keywords):
    """
    remove subkeywords
    """
    result = []
    sorted_keywords = sorted(keywords, key=len, reverse=True)
    
    for k in sorted_keywords:
        for rk in result:
            if rk.lower().startswith(k):
                break
        else:
            result.append(k)
            continue

    return result


vectorizer = None
kw_model = None

def init_keyword_extractor():
    global vectorizer
    global kw_model

    from keybert import KeyBERT
    import spacy
    from sklearn.feature_extraction.text import CountVectorizer

    kw_model = KeyBERT(model=spacy.load("ru_core_news_sm", exclude=['tokenizer', 'tagger', 'parser', 'ner', 'attribute_ruler', 'lemmatizer']))
    vocab = [" ".join(tokenize_sentence(s)) for s in vocab_raw]
    vectorizer = CountVectorizer(ngram_range=(1, 4), vocabulary=vocab, tokenizer=tokenize_sentence)

def extract_keywords(text):
    global vectorizer
    global kw_model

    if vectorizer is None or kw_model is None:
        init_keyword_extractor()

    keywords = [k for k, score in kw_model.extract_keywords(text, vectorizer=vectorizer)]
    return merge_keywords(canonical_keywords(keywords))