Скрытый семантический анализ в коде
Здравствуйте и добро пожаловать на заключительную статью по «Глубокое обучение без учителя».
В которой мы рассмотрим код для скрытого семантического анализа.
Если вы не хотите писать код самостоятельно, а лишь просмотреть его, перейдите по адресу https://github.com/lazyprogrammer/machine_learning_examples и зайдите в папку nlp_class. Нужные для данного примера файлы называются lsa.py и all_books_titkes.txt – последний и будет нашими данными. Они представляют собой список заглавий книг, по одному заглавию в каждой строке.
Итак, начинаем с того же, что и в семантическом анализе при предварительной обработке данных, и нам понадобятся те же библиотеки.
import nltk
import numpy as np
import matplotlib.pyplot as plt
from nltk.stem import WordNetLemmatizer
from sklearn.decomposition import TruncatedSVD
Инициируем наш лемматизатор и загрузим заглавия книг в массив.
wordnet_lemmatizer = WordNetLemmatizer()
titles = [line.rstrip() for line in open(‘all_book_titles.txt’)]
Мы вновь воспользуемся списком стоп-слов, поскольку в данных есть ряд слов, которые нам не нужны, а также расширим этот список. Я это уже сделал.
stopwords = set(w.rstrip() for w in open(‘stopwords.txt’))
stopwords = stopwords.union({
‘introduction’, ‘edition’, ‘series’, ‘application’,
‘approach’, ‘card’, ‘access’, ‘package’, ‘plus’, ‘etext’,
‘brief’, ‘vol’, ‘fundamental’, ‘guide’, ‘essential’, ‘printed’,
‘third’, ‘second’, ‘fourth’, })
Используем токенизатор из предыдущих занятий, но кое-что добавим в него. Дело в том, что в названиях книг часто встречаются записи вроде «второе издание», «третье издание», поэтому мы уберём токены, имеющие числа.
def my_tokenizer(s):
s = s.lower()
tokens = nltk.tokenize.word_tokenize(s)
tokens = [t for t in tokens if len(t) > 2]
tokens = [wordnet_lemmatizer.lemmatize(t) for t in tokens]
tokens = [t for t in tokens if t not in stopwords]
tokens = [t for t in tokens if not any(c.isdigit() for c in t)]
return tokens
Теперь то же, что было и при анализе тональности текста – вычисляем индекс каждого слова, пройдя по всему словарю.
word_index_map = {}
current_index = 0
all_tokens = []
all_titles = []
index_word_map = []
for title in titles:
try:
title = title.encode(‘ascii’, ‘ignore’)
all_titles.append(title)
tokens = my_tokenizer(title)
all_tokens.append(tokens)
for token in tokens:
if token not in word_index_map:
word_index_map[token] = current_index
current_index += 1
index_word_map.append(token)
except:
pass
Так же скопируем код функции tokens_to_vector, с тем разве что различием, что теперь у нас нет меток – это обучение без учителя.
def tokens_to_vector(tokens):
x = np.zeros(len(word_index_map))
for t in tokens:
i = word_index_map[t]
x[i] = 1
return x
Далее всё как прежде.
N = len(all_tokens)
D = len(word_index_map)
X = np.zeros((D, N))
i = 0
for tokens in all_tokens:
X[:,i] = tokens_to_vector(tokens)
i += 1
svd = TruncatedSVD()
Z = svd.fit_transform(X)
Теперь выведем результат на экран.
plt.scatter(Z[:,0], Z[:,1])
for i in xrange(D):
plt.annotate(s=index_word_map[i], xy=(Z[i,0], Z[i,1]))
plt.show()
Запустим нашу программу.
Видим, что слова «история» и «наука» расположены очень далеко друг от друга. «История», «искусство» и «том» – также далековато, но «компьютер» и «наука» находятся на одной оси. Приблизим наш маленький кластер.
Слова «статистика», «бизнес», «биология», «инженерия» находятся возле друг друга, а в другой части находятся слова «Америка», «глобальный», «книга», «мир», «современный». Увеличив ещё немного, увидим, что искусство, религия и социальные науки группируются ближе к верху, тогда как технические науки и математика – к низу.
Спасибо, что уделили свое время на изучение данного курса, в будущем ожидайте продолжение. Удачи!