Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Цифровая экономика в социальных сетях

..pdf
Скачиваний:
4
Добавлен:
20.11.2023
Размер:
8.95 Mб
Скачать

Рис. П2. Распределение цен на услуги по кластерам

Рис. П3. Изменение цен на услуги по кластерам в течение времени

191

Используемые библиотеки

import pandas as pd import re

import numpy as np

import matplotlib.pyplot as plt %matplotlib inline

import seaborn as sns sns.set(style="whitegrid")

Предобработка и обучение модели Word2Vec

Почистим поле «Название» от «мусора»

df['Название'] = df['Название'].replace(r'"', '', regex=True)

Определяем процедуру для токенизации текстового поля и проверяем ее работу

def tokenizer(test): test = test.lower()

test = re.findall(r'\b[а-яa-z]\w+', test) return test

#return ' '.join(test)

tokenizer('Привет в ТЕБЕ. 154. "Instagramm"

***Вконтакте***')

['привет', 'тебе', 'instagramm', 'вконтакте']

Токенизируем поле «Название» и проверяем результат

df['name_clr'] = df['Название'].map(lambda x: tokenizer(x))

df['name_clr'].sample(5)

3998 [акционное, предложение, обратным, отсче-

том, p...

2126 [пак, команды, для, взлома]

192

3875 [автоматически, рекомендуемые, товары]

5065 [контекстная, реклама]

4482 [admin, bar, middle, редактирование, товара, в...

Name: name_clr, dtype: object

Определяем класс для подсчета «усредненного» вектора слов, входящих в текстовое поле

class mean_vectorizer(object):

def __init__(self, word2vec): self.word2vec = word2vec

self.dim = len(next(iter(w2v.values())))

def fit(self, X): return self

def transform(self, X): return np.array([

np.mean([self.word2vec[w] for w in words if w in self.word2vec]

or [np.zeros(self.dim)],

axis=0)

for words in X

])

Создаем Word2Vec-модель

from gensim.models import word2vec

model = word2vec.Word2Vec(df['name_clr'], size=300, window=3, workers=-1)

model.corpus_count 5520

Создаем словарь из слов и соответствующим им векторов

w2v = dict(zip(model.wv.index2word, model.wv.syn0))

193

C:\Users\Plotnikov\anaconda3\lib\sitepackages\ipykernel_launcher.py:1: DeprecationWarning: Call to deprecated `syn0` (Attribute will be removed in 4.0.0, use self.vectors instead).

"""Entry point for launching an IPython kernel.

Накапливаем в массиве name_means усредненные вектора, соответсвующие названиям групп

name_lst = df['name_clr'].to_list() len(name_lst)

5520 name_means =

mean_vectorizer(w2v).fit(name_lst).transform(name_l st)

name_means.shape (5520, 300)

Кластеризуем усредненные вектора по принципу максимальной схожести

Рассмотрим четыре варианта кластеризаци: на 4, 8, 10, и 15 кластеров

4 кластера

clusters = 4

from sklearn.cluster import KMeans

n_clusters = clusters

km = KMeans(n_clusters=n_clusters) res = km.fit_predict(name_means) res.shape

(5520,)

Добавляем в основной датасет столбец с полученным номером кластера. И отображаем графическое представление распределения по кластерам

194

df['cluster_4'] = res sns.countplot(x='cluster_4', data=df);

Определим функцию для подсчета и выдачи наиболее частых слов в названии кластера

from collections import Counter

def most_common_words(words, top):

all_words = 0 dict_words = {} for word in words:

dict_words [word] = dict_words.get(word, 0)

+ 1

all_words +=1

c = Counter(dict_words) return c.most_common(top)

Смотрим наиболее частые слова в кластере 3

words_clust4 = df.Название[df.cluster_4==3].to_list()

most_common_words(words_clust4, 10)

Рассчитаем среднюю стоимость по кластеру, обозначив название кластера самым часто встречающимся в нем словом. Отобразим результат в графическом виде.

clusters = 8

key_words = []

for cl in range(clusters):

words = df.Название[df.cluster_8==cl].to_list() key_words.append(most_common_words(words,

1)[0][0])

195

price_by_cluster = df.groupby('cluster_8')['cluster_8','Цена'].mean() price_by_cluster['key_word'] = key_words

plt.figure(figsize=(12,4)) sns.barplot(price_by_cluster['key_word'], price_by_cluster['Цена'], alpha=0.9) plt.ylabel('Average price', fontsize=12) plt.xlabel('Cluster', fontsize=10) plt.xticks(rotation=90)

plt.show(); C:\Users\Plotnikov\anaconda3\lib\sitepackages\ipykernel_launcher.py:8: FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead.

Теперь посмотрим, как меняется цена на услуги по кластерам с течением времени. Для этого сгруппируем все данные выборки по периодам (квартал) и отобразим их на графике

for i in range(clusters): time_series = df[['Дата',

'Цена']][df['cluster_8']==i] time_series.set_index('Дата', inplace=True) time_series = time_series.resample('Q').mean()

#, how='mean') time_series['Цена'].plot(figsize=(19,10))

plt.ylabel('Цена') plt.legend(key_words) plt.grid(True) plt.show()

Визуализируем близость кластеров

196

Определим функцию уменьшения размерности векторов и визуализации

Matplotlib visualization

from sklearn.manifold import TSNE import matplotlib.cm as cm

def tsne_plot(labels, tokens, clusters): tsne_model = TSNE(perplexity=15,

n_components=2, init='pca', n_iter=3500, random_state=33)

new_values = tsne_model.fit_transform(tokens)

#Координаты в 2D всех элементов x = []

y = []

for value in new_values: x.append(value[0]) y.append(value[1])

#Список цветов кластеров

colors = ["steelblue", "sandybrown", "mediumseagreen", "indianred",

"mediumpurple", "tan", "plum", "dark-

gray"]

plt.figure(figsize=(16, 9))

# Определим количество элементов в каждом кластере

groups_count = []

for clus_number in range(clusters):

groups_count.append(len(df.name_clr[df.cluster_8==c lus_number]))

# Определим границы групп элементов каждого кластера

start, end = 0, 0 scope = []

197

for k in groups_count: end += k

scope.append((start, end)) start += k

# Визуализируем элементы кластеров x_for_cluster0, y_for_cluster0 =

x[scope[0][0]:scope[0][1]],

y[scope[0][0]:scope[0][1]] x_for_cluster1, y_for_cluster1 =

x[scope[1][0]:scope[1][1]],

y[scope[1][0]:scope[1][1]] x_for_cluster2, y_for_cluster2 =

x[scope[2][0]:scope[2][1]],

y[scope[2][0]:scope[2][1]] x_for_cluster3, y_for_cluster3 =

x[scope[3][0]:scope[3][1]],

y[scope[3][0]:scope[3][1]] x_for_cluster4, y_for_cluster4 =

x[scope[4][0]:scope[4][1]],

y[scope[4][0]:scope[4][1]] x_for_cluster5, y_for_cluster5 =

x[scope[5][0]:scope[5][1]],

y[scope[5][0]:scope[5][1]] x_for_cluster6, y_for_cluster6 =

x[scope[6][0]:scope[6][1]],

y[scope[6][0]:scope[6][1]] x_for_cluster7, y_for_cluster7 =

x[scope[7][0]:scope[7][1]],

y[scope[7][0]:scope[7][1]]

scat0 = plt.scatter(x_for_cluster0, y_for_cluster0, s=10, c=[colors[0]], alpha=0.65)

scat1 = plt.scatter(x_for_cluster1, y_for_cluster1, s=10, c=[colors[1]], alpha=0.65)

scat2 = plt.scatter(x_for_cluster2, y_for_cluster2, s=10, c=[colors[2]], alpha=0.65)

scat3 = plt.scatter(x_for_cluster3, y_for_cluster3, s=10, c=[colors[3]], alpha=0.65)

scat4 = plt.scatter(x_for_cluster4, y_for_cluster4, s=10, c=[colors[4]], alpha=0.65)

198

scat5 = plt.scatter(x_for_cluster5, y_for_cluster5, s=10, c=[colors[5]], alpha=0.65)

scat6 = plt.scatter(x_for_cluster6, y_for_cluster6, s=10, c=[colors[6]], alpha=0.65)

scat7 = plt.scatter(x_for_cluster7, y_for_cluster7, s=10, c=[colors[7]], alpha=0.65)

plt.legend((scat0, scat1, scat2, scat3, scat4, scat5, scat6, scat7), tuple(labels))

plt.grid(True)

plt.show()

Накапливаем в массиве tokens_means_lst усредненные вектора предварительно токенизированных полей «Название» соответсвующих кластеров

tokens_means_lst = [] samples = len(key_words)

for i in range(samples): tokens_lst =

df.name_clr[df.cluster_8==i].to_list() tokens_means =

mean_vectorizer(w2v).fit(tokens_lst).transform(toke ns_lst)

tokens_means_lst.extend(tokens_means) tsne_plot(key_words, tokens_means_lst, samples)

Seaborn visualization

# Понизим размерность усредненных векторов предварительно токенизированных полей Название, сохраним в массивы координат

tsne_model_2 = TSNE(perplexity=15, n_components=2, init='pca', n_iter=3500, random_state=33) new_values_2 = tsne_model_2.fit_transform(name_means)

199

x_2 = [] y_2 = []

for value_2 in new_values_2: x_2.append(value_2[0])

y_2.append(value_2[1])

# Сформируем датафрейм из координат и кластеров gf = pd.DataFrame({'X_2': x_2, 'Y_2': y_2, 'CLUSTERS': df.cluster_8})

gf.shape

(5520, 3)

# Заменим номера кластеров на названия

gf['CLUSTERS'] = gf['CLUSTERS'].replace({0: 'Абонемент на 4 занятия',

1:

'Интернет-магазин',

2:

'Продвижение сайта',

3:

'KILOBYTE | программа для 8-9 лет',

4:

'Разработка логотипа',

5:

'Landing Page',

6:

'Корпоративный сайт',

7:

'Программист 1с'})

# Визуализируем plt.figure(figsize=(16, 9))

sns.scatterplot(x="X_2", y="Y_2", hue="CLUSTERS", hue_order=key_words, data=gf, alpha=0.65, legend='full');

Дополнительно

Рассмотрим подробнее кластер 5 (при кластеризации на 8 кластеров). Посмотрим ТОП-10 самых часто используемых слов в названия групп, попавших в этот кластер

words = df.Название[df.cluster_8==5].to_list()

200