Векторные представления слов и работа с предобученными эмбедингами¶
Введение¶
Работа с векторным представлением слов¶
- В прошлый раз мы затронули тему векторного представления отдельных слов в докуметне (
BoW
,TF-IDF
) - Сегодня мы подаботаем с векторным представлением слов
word2vec
иfasttext
(используя библиотекуgensim
) - С
BoW
,TF-IDF
нам требовалось ограничивать простанственное представление так как количество столбцов зависит от длины словаря, что приводит к очень большим матрицам - В
word2vec
иfasttext
мы сопастовляем слову или предложению некое векторное представление любого постранственного размера
Векторизация слов из Твиттера¶
- В данном ноутбуке мы воспользуемся данными из твиттера, сохраненные в
csv
In [1]:
Copied!
pip install pymystem3
pip install pymystem3
Collecting pymystem3 Downloading pymystem3-0.2.0-py3-none-any.whl (10 kB) Requirement already satisfied: requests in /opt/conda/lib/python3.10/site-packages (from pymystem3) (2.31.0) Requirement already satisfied: charset-normalizer<4,>=2 in /opt/conda/lib/python3.10/site-packages (from requests->pymystem3) (3.1.0) Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.10/site-packages (from requests->pymystem3) (3.4) Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/conda/lib/python3.10/site-packages (from requests->pymystem3) (1.26.15) Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.10/site-packages (from requests->pymystem3) (2023.5.7) Installing collected packages: pymystem3 Successfully installed pymystem3-0.2.0 Note: you may need to restart the kernel to use updated packages.
Импортируем библиотеки¶
In [2]:
Copied!
import pandas as pd
import random
import numpy as np
from sklearn.metrics import *
from sklearn.feature_extraction.text import *
from sklearn.model_selection import train_test_split
from collections import Counter, defaultdict
import warnings
from pymystem3 import Mystem
import re
warnings.filterwarnings('ignore')
random.seed(1228)
import pandas as pd
import random
import numpy as np
from sklearn.metrics import *
from sklearn.feature_extraction.text import *
from sklearn.model_selection import train_test_split
from collections import Counter, defaultdict
import warnings
from pymystem3 import Mystem
import re
warnings.filterwarnings('ignore')
random.seed(1228)
/opt/conda/lib/python3.10/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5 warnings.warn(f"A NumPy version >={np_minversion} and <{np_maxversion}"
In [3]:
Copied!
df_pos = pd.read_csv("/kaggle/input/twitter/positive.csv", sep=';', header = None)
df_pos.tail()
df_pos = pd.read_csv("/kaggle/input/twitter/positive.csv", sep=';', header = None)
df_pos.tail()
Out[3]:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
114906 | 411368729235054592 | 1386912922 | diminlisenok | Спала в родительском доме, на своей кровати...... | 1 | 0 | 0 | 0 | 1497 | 56 | 34 | 2 |
114907 | 411368729424187392 | 1386912922 | qilepocagotu | RT @jebesilofyt: Эх... Мы немного решили сокра... | 1 | 0 | 1 | 0 | 692 | 225 | 210 | 0 |
114908 | 411368796537257984 | 1386912938 | DennyChooo | Что происходит со мной, когда в эфире #proacti... | 1 | 0 | 0 | 0 | 4905 | 448 | 193 | 13 |
114909 | 411368797447417856 | 1386912938 | bedowabymir | "Любимая,я подарю тебе эту звезду..." Имя како... | 1 | 0 | 0 | 0 | 989 | 254 | 251 | 0 |
114910 | 411368857035898880 | 1386912953 | Prituljak_Sibir | @Ma_che_rie посмотри #непытайтесьпокинутьомск ... | 1 | 0 | 0 | 0 | 1005 | 221 | 178 | 6 |
In [4]:
Copied!
df_neg = pd.read_csv("/kaggle/input/twitter/negative.csv", sep=';', header = None)
df_neg.head()
df_neg = pd.read_csv("/kaggle/input/twitter/negative.csv", sep=';', header = None)
df_neg.head()
Out[4]:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 408906762813579264 | 1386325944 | dugarchikbellko | на работе был полный пиддес :| и так каждое за... | -1 | 0 | 0 | 0 | 8064 | 111 | 94 | 2 |
1 | 408906818262687744 | 1386325957 | nugemycejela | Коллеги сидят рубятся в Urban terror, а я из-з... | -1 | 0 | 0 | 0 | 26 | 42 | 39 | 0 |
2 | 408906858515398656 | 1386325966 | 4post21 | @elina_4post как говорят обещаного три года жд... | -1 | 0 | 0 | 0 | 718 | 49 | 249 | 0 |
3 | 408906914437685248 | 1386325980 | Poliwake | Желаю хорошего полёта и удачной посадки,я буду... | -1 | 0 | 0 | 0 | 10628 | 207 | 200 | 0 |
4 | 408906914723295232 | 1386325980 | capyvixowe | Обновил за каким-то лешим surf, теперь не рабо... | -1 | 0 | 0 | 0 | 35 | 17 | 34 | 0 |
Предобработка данных¶
Две функции которые мы можем использовать для очистки данных из соцсетей
words_only
Оставляет только слова и символы которые могут быть полезны для смайликовlemmatize
Функция которая лемматизируем текст (используя pymystem3)
In [5]:
Copied!
# функция для предобработки с регулярками
def words_only(text):
try:
return " ".join(re.findall("[А-Яа-я:=!\)\()A-z\_\%/|]+",text))
except:
return ""
# функция для лемматизации с pymystem
lemmatiser = Mystem()
def lemmatize(text):
try:
return "".join(lemmatiser.lemmatize(text)).strip()
except:
return " "
words_only('g;iuhoikl 7.kjh 87h одлжд :))')
# функция для предобработки с регулярками
def words_only(text):
try:
return " ".join(re.findall("[А-Яа-я:=!\)\()A-z\_\%/|]+",text))
except:
return ""
# функция для лемматизации с pymystem
lemmatiser = Mystem()
def lemmatize(text):
try:
return "".join(lemmatiser.lemmatize(text)).strip()
except:
return " "
words_only('g;iuhoikl 7.kjh 87h одлжд :))')
Installing mystem to /root/.local/bin/mystem from http://download.cdn.yandex.net/mystem/mystem-3.1-linux-64bit.tar.gz
Out[5]:
'g iuhoikl kjh h одлжд :))'
In [6]:
Copied!
lemmatize('вечером или медленный')
lemmatize('вечером или медленный')
Out[6]:
'вечер или медленный'
In [7]:
Copied!
df_neg = pd.read_csv("/kaggle/input/twitter/negative.csv", sep=';', header = None, usecols = [3])
df_pos = pd.read_csv("/kaggle/input/twitter/positive.csv", sep=';', header = None, usecols = [3])
df_neg['sent'] = 'neg'
df_pos['sent'] = 'pos'
df_pos['text'] = df_pos[3]
df_neg['text'] = df_neg[3]
df = pd.concat([df_neg, df_pos])
df = df[['text', 'sent']]
%time df.text = df.text.apply(words_only)
#%time df.text = df.text.apply(lemmatize)
df_neg = pd.read_csv("/kaggle/input/twitter/negative.csv", sep=';', header = None, usecols = [3])
df_pos = pd.read_csv("/kaggle/input/twitter/positive.csv", sep=';', header = None, usecols = [3])
df_neg['sent'] = 'neg'
df_pos['sent'] = 'pos'
df_pos['text'] = df_pos[3]
df_neg['text'] = df_neg[3]
df = pd.concat([df_neg, df_pos])
df = df[['text', 'sent']]
%time df.text = df.text.apply(words_only)
#%time df.text = df.text.apply(lemmatize)
CPU times: user 1.36 s, sys: 40.2 ms, total: 1.4 s Wall time: 1.4 s
In [8]:
Copied!
print(df.shape)
#df.head()
print(df.shape)
#df.head()
(226834, 2)
Word2Vec
требует на входе токенизированные данные в формате списков
In [9]:
Copied!
texts = [df.text.iloc[i].split() for i in range(len(df))]
print(len(texts))
texts = [df.text.iloc[i].split() for i in range(len(df))]
print(len(texts))
226834
Обучаем модель Word2Vec¶
Эмбединговые представление можно получить обучив модель на наших данных из твитера
- На входе подаем список токенов всех документов в корпусе
text
- Контекстное окно будет +/- 5 слов
- Минимальная частота слов 5 (все что меньше игнорируется)
In [10]:
Copied!
%%time
from gensim.models import Word2Vec
# Тренируем модель
model = Word2Vec(texts,
window=5,
min_count=5,
workers=4)
# Сохраняем модель
model.save("word2v.model")
# Загружаем модель
#model = Word2Vec.load("word2v.model")
%%time
from gensim.models import Word2Vec
# Тренируем модель
model = Word2Vec(texts,
window=5,
min_count=5,
workers=4)
# Сохраняем модель
model.save("word2v.model")
# Загружаем модель
#model = Word2Vec.load("word2v.model")
CPU times: user 36.8 s, sys: 366 ms, total: 37.1 s Wall time: 13.2 s
Операции с векторами¶
Полезные word2vec
операции:
- Из модели можно выгрузить векторные представления слов с помощью
wv
- Мы можем найти наиболее близкие к слову слова используя
wv.most_similar
- С этими векторами мы можем делать вычисления и суммиование используя
wv.similar_by_vector
- Можем вычислить слова которые не вливаются в предложение используя
wv.doesnt_match
In [11]:
Copied!
model.wv['работа']
model.wv['работа']
Out[11]:
array([-0.10470013, 0.03513598, 0.41875052, 0.5153433 , 0.9402133 , -0.2930955 , 0.5164637 , 0.7244828 , -0.24704719, -0.27431324, -0.21855737, 0.01049238, -0.12207789, -0.257858 , 0.3303831 , -0.5363448 , 0.16048016, -0.00357761, -0.02529725, -0.896249 , 0.00231601, -0.09299509, 0.50959855, -0.41379848, -0.58466417, -0.59111625, 0.24317443, -0.27386442, -0.09665257, 0.02590754, 0.36794418, -0.578324 , -0.00952124, 0.15676403, 0.14984065, 0.28297207, 0.1306792 , 0.45648193, -0.4614138 , -0.00394126, -0.18601353, 0.28170818, -0.34839335, 0.46978518, 0.1506986 , 0.18715191, -0.05226476, -0.3970961 , -0.09965609, 0.16863827, 0.14389691, -0.1783841 , -0.37686712, 0.22169474, -0.38901794, 0.35773337, -0.08235621, 0.2484024 , -0.31825948, 0.02456559, -0.04911847, 0.01784658, 0.9772008 , -0.03402596, -0.7810176 , 0.17957872, 0.5262285 , 0.41534203, -0.5283286 , -0.20104289, -0.22328393, -0.07975829, 0.24007888, 0.47399127, 0.2318192 , 0.04374537, 0.43821317, 0.78923124, -0.7456475 , 0.543595 , -0.1420232 , -0.61270565, -0.18691902, -0.40484717, -0.2623664 , 0.24123536, 0.17079079, 0.29155582, 0.66039234, -0.15984882, 0.35916597, -0.24354032, -0.10610883, 1.0515662 , 0.50824046, 0.69234437, 0.4339073 , -0.12926975, -0.37009227, -0.17433347], dtype=float32)
In [12]:
Copied!
model.wv.most_similar("работа")
model.wv.most_similar("работа")
Out[12]:
[('школа', 0.8297739624977112), ('учеба', 0.8025556802749634), ('физика', 0.7936404347419739), ('ужасная', 0.7904353737831116), ('погода', 0.785150408744812), ('настоящая', 0.7794501781463623), ('сессия', 0.766066312789917), ('пара', 0.7567639946937561), ('елка', 0.75386643409729), ('алгебра', 0.7523488402366638)]
In [13]:
Copied!
vec = (model.wv['университет'] - model.wv['студент'] + model.wv['школьник'])/3
model.wv.similar_by_vector(vec)
vec = (model.wv['университет'] - model.wv['студент'] + model.wv['школьник'])/3
model.wv.similar_by_vector(vec)
Out[13]:
[('университет', 0.9683309197425842), ('поступлении', 0.9346603751182556), ('попросили', 0.9012249708175659), ('Конгениальность!!!', 0.835422158241272), ('При', 0.821401059627533), ('принести', 0.821234405040741), ('рукав', 0.7973737716674805), ('Мисс', 0.7918796539306641), ('исполнить', 0.784400224685669), ('сторону)', 0.761738657951355)]
In [14]:
Copied!
model.wv.doesnt_match("цветок дерево кактус еда".split())
model.wv.doesnt_match("цветок дерево кактус еда".split())
Out[14]:
'цветок'
Понижение размерности векторов¶
Для визуализации многомерного вектора в двухмерном пространстве
- Найдем наиболее часто всречаемые слова в корпусе, будем отображать только часть слов (топ 500)
- Визуализируем векторное пространство слов с помощью метода понижения пространств
TSNE
(manifold learning)
In [15]:
Copied!
from collections import Counter
counter = Counter()
top_words = []
for text in texts:
counter.update(text)
for i in counter.most_common(500):
top_words.append(i[0])
print(top_words[:10])
from collections import Counter
counter = Counter()
top_words = []
for text in texts:
counter.update(text)
for i in counter.most_common(500):
top_words.append(i[0])
print(top_words[:10])
['не', 'и', 'в', 'я', 'RT', 'на', 'что', 'http://t', 'а', 'с']
Выберем векторное представление выбранных слов
In [16]:
Copied!
top_words_vec = model.wv[top_words]
print(top_words_vec.shape)
top_words_vec = model.wv[top_words]
print(top_words_vec.shape)
(500, 100)
Мы можем еще кластиризивать слова на подгруппы с помощью агломеративной кластеризации из sklearn
In [17]:
Copied!
from sklearn.manifold import TSNE
from sklearn.cluster import AgglomerativeClustering
# TSNE manifold learning
tsne = TSNE(n_components=2,
random_state=0)
# Agglomerative Clusterisation
htop_words_tsne = tsne.fit_transform(top_words_vec)
htop_words_tsne[:10,:]
from sklearn.manifold import TSNE
from sklearn.cluster import AgglomerativeClustering
# TSNE manifold learning
tsne = TSNE(n_components=2,
random_state=0)
# Agglomerative Clusterisation
htop_words_tsne = tsne.fit_transform(top_words_vec)
htop_words_tsne[:10,:]
Out[17]:
array([[-17.201815 , -10.581679 ], [ -5.498273 , 1.1501819 ], [ 24.924892 , 5.29755 ], [-22.047146 , -12.7216425 ], [ 4.926873 , 7.4602714 ], [ 25.276384 , 12.435881 ], [ -1.6100953 , -23.253643 ], [-16.26932 , -0.80900466], [ 25.187656 , -2.175251 ], [ -2.679728 , 15.2672615 ]], dtype=float32)
Кластеризация и визуализация слов¶
- Воспользуемся методом
AgglomerativeClustering
из библиотекиsklearn
для того чтобы сгруппировать похожие слова в группы, в этом подходе кластеризации мы сами должны определить на сколько кластеров мы разбиваем данные - Получив кластерное пренодлежность для каждого слово, визуализируем результаты с помощью библиотеки
bokeh
In [18]:
Copied!
model = AgglomerativeClustering(n_clusters=5)
clusters = model.fit_predict(htop_words_tsne)
clusters = list(clusters)
clusters = list(map(str, clusters))
# combine data
data = pd.DataFrame({'d1':htop_words_tsne[:,0],
'd2':htop_words_tsne[:,1],
'cluster':clusters,
'names':top_words})
model = AgglomerativeClustering(n_clusters=5)
clusters = model.fit_predict(htop_words_tsne)
clusters = list(clusters)
clusters = list(map(str, clusters))
# combine data
data = pd.DataFrame({'d1':htop_words_tsne[:,0],
'd2':htop_words_tsne[:,1],
'cluster':clusters,
'names':top_words})
In [19]:
Copied!
from bokeh.models import ColumnDataSource, LabelSet
from bokeh.models import LinearColorMapper, ColorBar
from bokeh.plotting import figure, show, output_file
from bokeh.transform import transform
from bokeh.palettes import GnBu3, OrRd3
from bokeh.io import output_notebook
from bokeh.transform import factor_cmap
import colorcet as cc
output_notebook()
p = figure(tools="pan,wheel_zoom,reset,save",
toolbar_location="above",
title="word2vec T-SNE for most common words")
color = LinearColorMapper(palette = 'Viridis256')
p.scatter(x="d1", y="d2",
fill_color = transform('cluster', color),
line_color='black',
size=8 ,
source=data)
labels = LabelSet(x="d1", y="d2", text="names", y_offset=6,
text_font_size="8pt", text_color="#555555",
source=ColumnDataSource(data), text_align='center')
p.add_layout(labels)
show(p)
from bokeh.models import ColumnDataSource, LabelSet
from bokeh.models import LinearColorMapper, ColorBar
from bokeh.plotting import figure, show, output_file
from bokeh.transform import transform
from bokeh.palettes import GnBu3, OrRd3
from bokeh.io import output_notebook
from bokeh.transform import factor_cmap
import colorcet as cc
output_notebook()
p = figure(tools="pan,wheel_zoom,reset,save",
toolbar_location="above",
title="word2vec T-SNE for most common words")
color = LinearColorMapper(palette = 'Viridis256')
p.scatter(x="d1", y="d2",
fill_color = transform('cluster', color),
line_color='black',
size=8 ,
source=data)
labels = LabelSet(x="d1", y="d2", text="names", y_offset=6,
text_font_size="8pt", text_color="#555555",
source=ColumnDataSource(data), text_align='center')
p.add_layout(labels)
show(p)
Предобученные эмбединги¶
Доподнение¶
- (1) Зайдите на сайт RusVectores и скачайте одну из предобученных моделей gensim
- (2) Проведите аналогичные эксперименты с использованием скачанных векторных представлений
Для нашей задачи возьмем предобученные эмбеддинги (варианты без тагсет)
- geowac_lemmas_none_fasttextskipgram_300_5_2020
- Тагсет это дополнение к слову (например NOUN_дерево)
Утилизация Векторов¶
- Для того чтобы использовать предобученные эмбединги, сохраним модель на локальном диске
- Данная модель была обучена с помощью метода
fasttext
на большом русскоязычным корпусе - Вектора можно использовать в разных целях; в данноом ноутбуке мы просто их визуализируем
In [20]:
Copied!
import gensim
import urllib.request
import zipfile
# название и URL
we_models = {"geowac_lemmas_none_fasttextskipgram_300_5_2020": "http://vectors.nlpl.eu/repository/20/213.zip",}
import gensim
import urllib.request
import zipfile
# название и URL
we_models = {"geowac_lemmas_none_fasttextskipgram_300_5_2020": "http://vectors.nlpl.eu/repository/20/213.zip",}
In [21]:
Copied!
# сохраняем модель
def get_models(model_url, model_name, path_to_save="/kaggle/working/"):
model_path = path_to_save + model_name + ".zip"
urllib.request.urlretrieve(model_url, model_path)
for model_name, model_url in we_models.items():
get_models(model_url, model_name)
# сохраняем модель
def get_models(model_url, model_name, path_to_save="/kaggle/working/"):
model_path = path_to_save + model_name + ".zip"
urllib.request.urlretrieve(model_url, model_path)
for model_name, model_url in we_models.items():
get_models(model_url, model_name)
Разархивируем Модель¶
- Разархивируем скаченные данные и в зависимости от формата загружаем либо
Word2Vec
либоFasttext
- Загруженной нами модель размерность 300
- Предобученные модели нельзя дообуить данные векторов хранятся в
KeyedVectors
In [22]:
Copied!
# Функция для чтения word2vec / FastText
def open_model(model_name,model_path, is_fasttext = True):
# word2vec (model.bin)
if is_fasttext == False:
model_file = model_path + model_name + ".zip"
with zipfile.ZipFile(model_file, 'r') as archive:
stream = archive.open('model.bin')
model = gensim.models.KeyedVectors.load_word2vec_format(stream, binary=True)
# fasttext (model.model)
else:
model_file = model_path + model_name
model = gensim.models.KeyedVectors.load(model_file + "/model.model")
return model
with zipfile.ZipFile("/kaggle/working/geowac_lemmas_none_fasttextskipgram_300_5_2020.zip", 'r') as zip_ref:
zip_ref.extractall("/kaggle/working/geowac_lemmas_none_fasttextskipgram_300_5_2020")
# Функция для чтения word2vec / FastText
def open_model(model_name,model_path, is_fasttext = True):
# word2vec (model.bin)
if is_fasttext == False:
model_file = model_path + model_name + ".zip"
with zipfile.ZipFile(model_file, 'r') as archive:
stream = archive.open('model.bin')
model = gensim.models.KeyedVectors.load_word2vec_format(stream, binary=True)
# fasttext (model.model)
else:
model_file = model_path + model_name
model = gensim.models.KeyedVectors.load(model_file + "/model.model")
return model
with zipfile.ZipFile("/kaggle/working/geowac_lemmas_none_fasttextskipgram_300_5_2020.zip", 'r') as zip_ref:
zip_ref.extractall("/kaggle/working/geowac_lemmas_none_fasttextskipgram_300_5_2020")
In [23]:
Copied!
# загружаем KeyedVectors эмбеддинговый вектора
geowac_model = open_model('geowac_lemmas_none_fasttextskipgram_300_5_2020','/kaggle/working/')
# загружаем KeyedVectors эмбеддинговый вектора
geowac_model = open_model('geowac_lemmas_none_fasttextskipgram_300_5_2020','/kaggle/working/')
In [24]:
Copied!
top_words_vec = geowac_model[top_words]
print(top_words_vec.shape)
top_words_vec = geowac_model[top_words]
print(top_words_vec.shape)
(500, 300)
Визуализируем векторные представление¶
Как и в прошлом разделе визуализируем самы часто встречаюшихся слов и кластеризуем их на группы
In [25]:
Copied!
from sklearn.manifold import TSNE
from sklearn.cluster import AgglomerativeClustering
from bokeh.models import ColumnDataSource, LabelSet
from bokeh.models import LinearColorMapper
from bokeh.plotting import figure, show, output_file
from bokeh.transform import transform
from bokeh.io import output_notebook
def visualise_clusters(data):
'''
Vector Dimension Reduction
'''
# TSNE manifold learning
tsne = TSNE(n_components=2,
random_state=0)
# Agglomerative Clusterisation
htop_words_tsne = tsne.fit_transform(data)
htop_words_tsne[:10,:]
'''
Clusterise
'''
model = AgglomerativeClustering(n_clusters=10)
clusters = model.fit_predict(htop_words_tsne)
clusters = list(clusters)
clusters = list(map(str, clusters))
# combine data
data = pd.DataFrame({'d1':htop_words_tsne[:,0],
'd2':htop_words_tsne[:,1],
'cluster':clusters,
'names':top_words})
'''
Plot Cluster
'''
output_notebook()
p = figure(tools="pan,wheel_zoom,reset,save",
toolbar_location="above",
title="word2vec T-SNE for most common words")
color = LinearColorMapper(palette = 'Viridis256')
p.scatter(x="d1", y="d2",
fill_color = transform('cluster', color),
line_color='black',
size=8 ,
source=data)
labels = LabelSet(x="d1", y="d2", text="names", y_offset=6,
text_font_size="8pt", text_color="#555555",
source=ColumnDataSource(data), text_align='center')
p.add_layout(labels)
show(p)
from sklearn.manifold import TSNE
from sklearn.cluster import AgglomerativeClustering
from bokeh.models import ColumnDataSource, LabelSet
from bokeh.models import LinearColorMapper
from bokeh.plotting import figure, show, output_file
from bokeh.transform import transform
from bokeh.io import output_notebook
def visualise_clusters(data):
'''
Vector Dimension Reduction
'''
# TSNE manifold learning
tsne = TSNE(n_components=2,
random_state=0)
# Agglomerative Clusterisation
htop_words_tsne = tsne.fit_transform(data)
htop_words_tsne[:10,:]
'''
Clusterise
'''
model = AgglomerativeClustering(n_clusters=10)
clusters = model.fit_predict(htop_words_tsne)
clusters = list(clusters)
clusters = list(map(str, clusters))
# combine data
data = pd.DataFrame({'d1':htop_words_tsne[:,0],
'd2':htop_words_tsne[:,1],
'cluster':clusters,
'names':top_words})
'''
Plot Cluster
'''
output_notebook()
p = figure(tools="pan,wheel_zoom,reset,save",
toolbar_location="above",
title="word2vec T-SNE for most common words")
color = LinearColorMapper(palette = 'Viridis256')
p.scatter(x="d1", y="d2",
fill_color = transform('cluster', color),
line_color='black',
size=8 ,
source=data)
labels = LabelSet(x="d1", y="d2", text="names", y_offset=6,
text_font_size="8pt", text_color="#555555",
source=ColumnDataSource(data), text_align='center')
p.add_layout(labels)
show(p)