Тематическое моделирование - это тип статистического моделирования для выявления абстрактных тем, которые встречаются в коллекции документов. Скрытое размещение Дирихле (LDA) является примером тематической модели и используется для классификации текста в документе по определенной теме. Он строит тему для модели документа и слова для модели темы, смоделированные как распределения Дирихле.
Здесь мы собираемся применить LDA к набору документов и разделить их на темы. Давайте начнем!
Данные
Набор данных, который мы будем использовать, представляет собой список из более чем миллиона заголовков новостей, опубликованных за период 15 лет, которые можно загрузить с Kaggle.
import pandas as pd data = pd.read_csv('abcnews-date-text.csv', error_bad_lines=False); data_text = data[['headline_text']] data_text['index'] = data_text.index documents = data_text
Взгляните на данные.
print(len(documents)) print(documents[:5])
1048575
Предварительная обработка данных
Выполним следующие действия:
- Токенизация: разделите текст на предложения, а предложения - на слова. Слова в нижнем регистре и удаление знаков препинания.
- Слова, содержащие менее 3 символов, удаляются.
- Все игнорируемые слова удалены.
- Слова лемматизируются - слова от третьего лица заменяются на первое, а глаголы в прошедшем и будущем времени заменяются на настоящее.
- Слова выделены - слова сокращаются до их корневой формы.
Загрузка библиотек gensim и nltk
import gensim from gensim.utils import simple_preprocess from gensim.parsing.preprocessing import STOPWORDS from nltk.stem import WordNetLemmatizer, SnowballStemmer from nltk.stem.porter import * import numpy as np np.random.seed(2018) import nltk nltk.download('wordnet')
[nltk_data] Загрузка пакета wordnet в
[nltk_data] C: \ Users \ SusanLi \ AppData \ Roaming \ nltk_data…
[nltk_data] Пакет wordnet уже обновлен!
Верно
Напишите функцию для выполнения шагов лемматизации и предварительной обработки набора данных.
def lemmatize_stemming(text): return stemmer.stem(WordNetLemmatizer().lemmatize(text, pos='v')) def preprocess(text): result = [] for token in gensim.utils.simple_preprocess(text): if token not in gensim.parsing.preprocessing.STOPWORDS and len(token) > 3: result.append(lemmatize_stemming(token)) return result
Выберите документ для предварительного просмотра после предварительной обработки.
doc_sample = documents[documents['index'] == 4310].values[0][0] print('original document: ') words = [] for word in doc_sample.split(' '): words.append(word) print(words) print('\n\n tokenized and lemmatized document: ') print(preprocess(doc_sample))
исходный документ:
[«дождь», «помогает», «тушить», «лесные пожары»]
токенизированный и лемматизированный документ:
[«дождь», «помощь», «увлажнение», «бушфир»]
Это сработало!
Предварительно обработайте текст заголовка, сохранив результаты как «loaded_docs»
processed_docs = documents['headline_text'].map(preprocess) processed_docs[:10]
Мешок слов в наборе данных
Создайте словарь из «processing_docs», в котором будет указано, сколько раз слово встречается в обучающем наборе.
dictionary = gensim.corpora.Dictionary(processed_docs) count = 0 for k, v in dictionary.iteritems(): print(k, v) count += 1 if count > 10: break
0 трансляций
1 сообщество
2 решающих
3 лицензии
4 награды
5 клеветы
6 умов
7 звонков
8 инфраструктур
9 защиты
10 саммит
Gensim filter_extremes
Отфильтровать токены, которые появляются в
- менее 15 документов (абсолютное количество) или
- более 0,5 документа (часть от общего размера корпуса, а не абсолютное количество).
- после двух вышеуказанных шагов оставьте только первые 100000 наиболее часто используемых токенов.
dictionary.filter_extremes(no_below=15, no_above=0.5, keep_n=100000)
Gensim doc2bow
Для каждого документа мы создаем словарь, в котором указывается, сколько
слов и сколько раз они встречаются. Сохраните это в "bow_corpus", затем проверьте ранее выбранный нами документ.
bow_corpus = [dictionary.doc2bow(doc) for doc in processed_docs] bow_corpus[4310]
[(76, 1), (112, 1), (483, 1), (3998, 1)]
Предварительный просмотр пакета слов для нашего образца предварительно обработанного документа.
bow_doc_4310 = bow_corpus[4310] for i in range(len(bow_doc_4310)): print("Word {} (\"{}\") appears {} time.".format(bow_doc_4310[i][0], dictionary[bow_doc_4310[i][0]], bow_doc_4310[i][1]))
Слово 76 («бушфир») появляется 1 раз.
Слово 112 («справка») появляется 1 раз.
Слово 483 («дождь») появляется 1 раз.
Word 3998 («увлажняющий») появляется 1 раз.
TF-IDF
Создайте объект модели tf-idf с помощью models.TfidfModel на «bow_corpus» и сохраните его в «tfidf», затем примените преобразование ко всему корпусу и назовите его «corpus_tfidf». Наконец, мы предварительно просматриваем оценки TF-IDF для нашего первого документа.
from gensim import corpora, models tfidf = models.TfidfModel(bow_corpus) corpus_tfidf = tfidf[bow_corpus] from pprint import pprint for doc in corpus_tfidf: pprint(doc) break
[(0, 0.5907943557842693),
(1, 0.3900924708457926),
(2, 0.49514546614015836),
(3, 0.5036078441840635)]
Запуск LDA с помощью пакета слов
Обучите нашу модель lda с помощью gensim.models.LdaMulticore и сохраните ее в lda_model.
lda_model = gensim.models.LdaMulticore(bow_corpus, num_topics=10, id2word=dictionary, passes=2, workers=2)
Для каждой темы мы исследуем слова, встречающиеся в этой теме, и их относительный вес.
for idx, topic in lda_model.print_topics(-1): print('Topic: {} \nWords: {}'.format(idx, topic))
Можете ли вы различать разные темы, используя слова в каждой теме и их соответствующие веса?
Запуск LDA с использованием TF-IDF
lda_model_tfidf = gensim.models.LdaMulticore(corpus_tfidf, num_topics=10, id2word=dictionary, passes=2, workers=4) for idx, topic in lda_model_tfidf.print_topics(-1): print('Topic: {} Word: {}'.format(idx, topic))
Опять же, можете ли вы различать разные темы, используя слова в каждой теме и их соответствующие веса?
Оценка эффективности путем классификации образца документа с использованием модели LDA Bag of Words
Мы проверим, где будет классифицироваться наш тестовый документ.
processed_docs[4310]
[«дождь», «помощь», «увлажнение», «бушфир»]
for index, score in sorted(lda_model[bow_corpus[4310]], key=lambda tup: -1*tup[1]): print("\nScore: {}\t \nTopic: {}".format(score, lda_model.print_topic(index, 10)))
Наш тестовый документ имеет наибольшую вероятность быть частью темы, назначенной нашей моделью, а именно точной классификации.
Оценка эффективности путем классификации образца документа с использованием модели LDA TF-IDF.
for index, score in sorted(lda_model_tfidf[bow_corpus[4310]], key=lambda tup: -1*tup[1]): print("\nScore: {}\t \nTopic: {}".format(score, lda_model_tfidf.print_topic(index, 10)))
Наш тестовый документ имеет наибольшую вероятность быть частью темы, назначенной нашей моделью, а именно точной классификации.
Тестирование модели на невидимом документе
unseen_document = 'How a Pentagon deal became an identity crisis for Google' bow_vector = dictionary.doc2bow(preprocess(unseen_document)) for index, score in sorted(lda_model[bow_vector], key=lambda tup: -1*tup[1]): print("Score: {}\t Topic: {}".format(score, lda_model.print_topic(index, 5)))
Исходный код можно найти на Github. Я с нетерпением жду любых отзывов или вопросов.
Ссылка: