/Кластеризация ключевых фраз для контекстной рекламы LSA алгоритмом

Кластеризация ключевых фраз для контекстной рекламы LSA алгоритмом

Простой и крайне эффективный метод кластеризации фраз на смысловые группы.


Изображение 1. Визуализация LSA-алгоритма

Обобщенно алгоритм состоит из следующих шагов:

  1. Получаем частотную матрицу для нормальной формы фраз, встречающихся в выборке 2 или более раз
  2. Матрицу можно заменить на бинарную (есть слово во фразе или нет) или на TF-IDF интерпретацию (должна возрасти точность)
  3. Полученную матрицу преобразуем с помощью сингулярного разложения SVD
  4. Результирующую матрицу W (третья матрица полученная после разложения) отражает вложение фразу в группы
  5. Выбираем число k — количество (примерное) групп в тексте
  6. Разбираем матрицу W на векторы T1..n (по числу документов) длинной k
  7. Вычисляем косинусоидальные расстояние между векторами
  8. Сравниваем с порогом 0.1 и получаем группы фраз
# -*- coding:utf-8 -*-
"""LSA.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1HBCMt6VBLWLhHWMultp9AQz3a3Li5GQx

Устанавливаем нужные библиотеки
"""

!pip install pymorphy2

"""Импортируем нужные модули"""

import pymorphy2
import numpy
import random
from collections import Counter

"""Определяем функцию косинусного расстояния между двумя векторами"""

def cosine_distance(a, b):
    if len(a) != len(b):
      raise Exception(ValueError, "a and b must be same length")
    numerator = 0
    denoma = 0
    denomb = 0
    for i in range(len(a)):
      ai = a[i]
      bi = b[i]
      numerator += ai*bi
      denoma += ai*ai
      denomb += bi*bi
    result = 1 - numerator / (numpy.sqrt(denoma)*numpy.sqrt(denomb))
    return result

morph = pymorphy2.MorphAnalyzer()

word_list = [u'машина после мойки зимой',
             u'новое красивое платье купить в Москве',
             u'что делать после мойки машины зимой',
             u'мойка машины зимой на улице',
             u'не открывается машина после мойки зимой',
             u'как убрать жир с живота и боков',
             u'как быстро убрать живот бока домашних',
             u'поможет убрать живот бока',
             u'крутить обруч убрать живот бока',
             u'способы убрать живот и бока',
             u'подрезать яблоню весной',
             u'можно ли подрезать яблони зимой',
             u'правильно подрезать яблоню',
             u'подрезать яблоню весной видео',
             u'поменять задние тормозные колодки',
             u'поменять тормозные колодки на тойоте',
             u'поменять тормозные колодки на опель',
             u'самому поменять тормозные колодки',
             u'поменять тормозные колодки приора',
             u'купить детское нарядное платье',
             u'нарядные платья купить магазин',
             u'купить нарядное платье интернете',
             u'купить нарядное платье в интернет магазине',
             u'купить нарядное платье для женщины',
             u'купить нарядное платье недорого',
             u'синтетическое моторное масло роснефть отзывы',
             u'синтетическое моторное масло лукойл 5w40 отзывы',
             u'profix масло моторное синтетическое отзывы',
             u'синтетическое моторное масло 5w40 рольф отзывы',
             u'синтетическое моторное масло тнк 5w40 отзывы']
random.shuffle(word_list)
result_array = {}
result_array_f = {}
i = 0;
for l in word_list:
    result_array['T'+str(i)] = l
    result_array_f['T'+str(i)] = 0
    i = i + 1
w_norm = []
all_w_norm = [];
i = 0;
for l in word_list:
    words = l.split(' ')
    w_norm.append([])
    w_str = '';
    for w in words:
        w_one_norm = morph.parse(w)[0].normal_form
        w_norm[i].append( w_one_norm )
        all_w_norm.append( w_one_norm )
        w_str = w_str + ' ' + w_one_norm;
    result_array['T'+str(i)] = w_str
    i = i + 1
f_word = Counter(all_w_norm)
f_word_m = {};
for key, l in f_word.items():
    if (l >= 2 and len(key) > 1):
        f_word_m[key] = l;
i = 0;
f_matrix = []
for l in f_word_m:
    f_matrix.append([]);
    for l1 in w_norm:
        l1_f = Counter(l1);
        if (l in l1_f):
            f_matrix[i].append(l1_f[l]);
            print (l1_f[l], end='')
        else:
            print ('0', end='')
            f_matrix[i].append(0);
    print ('');
    i = i + 1;
a = numpy.array(f_matrix);
a,b,c = numpy.linalg.svd(a);
v_result = [];
for i in range(0, len(c[0])):
    v_result.append([]);
#число тематик
k = 6;
i = 0;
for l in range(0, k):
    for j in range(0, len(c[l])):
        v_result[j].append(c[l][i]);
        i = i + 1;
    i = 0;
i = 0; i1 = 0;
for v in v_result:
    print(v)
    if (result_array_f['T'+str(i)] == 0):
        result_array_f['T'+str(i)] = 1;
        print ('-------'+result_array['T'+str(i)]+'-------')
        for v1 in v_result:
            if (i1 != i):
                c = cosine_distance(v, v1);
                if (c <= 0.1):
                    print (result_array['T'+str(i1)]);
                    result_array_f['T'+str(i1)] = 1;
            i1 = i1 + 1;
        i1 = 0;
    i = i + 1;
Результаты кластеризации

0 0 0 0 1 0 0 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0
0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 1 0 0 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0
0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0
1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0
0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0
0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0

——- можно ли подрезать яблоня зимой——-
подрезать яблоня весной
подрезать яблоня весной видео
правильно подрезать яблоня
——- купить нарядный платье недорого——-
нарядный платье купить магазин
купить нарядный платье для женщина
новое красивый платье купить в москва
купить нарядный платье интернет
купить детский нарядный платье
купить нарядный платье в интернет магазин
——- синтетический моторный масло тнк 5w40 отзыв——-
profix масло моторный синтетический отзыв
синтетический моторный масло 5w40 рольф отзыв
синтетический моторный масло роснефть отзыв
синтетический моторный масло лукойл 5w40 отзыв
——- помочь убрать живот бок——-
как убрать жир с живот и боков
как быстро убрать живот бок домашний
крутить обруч убрать живот бок
способ убрать живот и бок
——- мойка машина зимой на улица——-
машина после мойка зимой
не открываться машина после мойка зимой
что делать после мойка машина зимой
——- поменять тормозной колодка приор——-
поменять тормозной колодка на тойота
поменять тормозной колодка на опель
поменять задний тормозной колодка
самый поменять тормозной колодка

Рабочий пример можно посмотреть и запустить по ссылке: https://colab.research.google.com/drive/1HBCMt6VBLWLhHWMultp9AQz3a3Li5GQx?usp=sharing