книги / Цифровая экономика в социальных сетях
..pdfРис. П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