Практические руководства

Руководство по OCTIS для новичков: оптимизация и сравнение тематических моделей - это просто

Пакет Python с наибольшим количеством интегрированных современных тематических моделей.

Тематические модели являются многообещающими методами генеративной статистики, которые направлены на извлечение скрытых тем, лежащих в основе коллекции документов. Обычно тематические модели имеют на выходе две матрицы.

1. Матрица тем-слов (словарь x number_topics), которая указывает вероятность появления слова i в теме k.

2. Тема-документ-матрица (количество_тем x количество_документов).

Затем для представления темы используются первые n слов из этой матрицы с наибольшей вероятностью.

Самый популярный метод моделирования тем - это скрытое распределение Дирихле, и о его работе и реализации написано много статей. Однако сосредоточение внимания только на LDA является ограничительным и может быть неоптимальным для данного корпуса. Для данного корпуса лучше подойдут другие тематические модели.

Недавно был выпущен новый пакет Python, OCTIS (Оптимизация и сравнение тематических моделей - это просто!). Судя по названию, вас не удивит, что OCTIS позволяет легко сравнивать тематические модели. Пакет содержит несколько тематических моделей, наборов данных, оценочных показателей и вариантов оптимизации.

В этом блоге я демонстрирую, как начать работу с пакетом. В следующих блогах я более подробно расскажу об оптимизации и сравнении тематических моделей.

Начнем с установки пакета:

pip install octis

Нам нужен набор данных.

from octis.dataset.dataset import Dataset

OCTIS имеет четыре встроенных набора данных:

Пойдем с самым маленьким:

dataset = Dataset()
dataset.fetch_dataset('BBC_news')

Чтобы выбрать другие наборы данных, выберите одно из имен в таблице (обратите внимание, что написание «BBC_news» в коде отличается от написания в таблице. Остальные имена такие же).

Теперь посмотрим, как выглядит набор данных:

len(dataset._Dataset__corpus)
>>> 2225
len(dataset._Dataset__vocabulary)
>>> 2949
print(dataset._Dataset__corpus[0:5])
>>> [[‘broadband’, ‘ahead’, ‘join’, ‘internet’, ‘fast’, ‘accord’, ‘official’, ‘figure’, ‘number’, ‘business’, ‘connect’, ‘jump’, ‘report’, ‘broadband’, ‘connection’, ‘end’, ‘compare’, ‘nation’, ‘rank’, ‘world’, ‘telecom’, ‘body’, ‘election’, ‘campaign’, ‘ensure’, ‘affordable’, ‘high’, ‘speed’, ‘net’, ‘access’, ‘american’, ‘accord’, ‘report’, ‘broadband’, ‘increasingly’, ‘popular’, ‘research’, ‘shopping’, ‘download’, ‘music’, ‘watch’, ‘video’, ‘total’, ‘number’, ‘business’, ‘broadband’, ‘rise’, ‘end’, ‘compare’, ‘hook’, ‘broadband’, ‘subscriber’, ‘line’, ‘technology’, ‘ordinary’, ‘phone’, ‘line’, ‘support’, ‘high’, ‘data’, ‘speed’, ‘cable’, ‘lead’, ‘account’, ‘line’, ‘broadband’, ‘phone’, ‘line’, ‘connection’, ‘accord’, ‘figure’],
[‘plan’, ‘share’, ‘sale’, ‘owner’, ‘technology’, ‘dominate’, ‘index’, ‘plan’, ‘sell’, ‘share’, ‘public’, ‘list’, ‘market’, ‘operate’, ‘accord’, ‘document’, ‘file’, ‘stock’, ‘market’, ‘plan’, ‘raise’, ‘sale’, ‘observer’, ‘step’, ‘close’, ‘full’, ‘public’, ‘icon’, ‘technology’, ‘boom’, ‘recently’, ‘pour’, ‘cold’, ‘water’, ‘suggestion’, ‘company’, ‘sell’, ‘share’, ‘private’, ‘technically’, ‘public’, ‘stock’, ‘start’, ‘trade’, ‘list’, ‘equity’, ‘trade’, ‘money’, ‘sale’, ‘investor’, ‘buy’, ‘share’, ‘private’, ‘filing’, ‘document’, ‘share’, ‘technology’, ‘firm’, ‘company’, ‘high’, ‘growth’, ‘potential’, ‘symbol’, ‘internet’, ‘telecom’, ‘boom’, ‘bubble’, ‘burst’, ‘recovery’, ‘fortune’, ‘tech’, ‘giant’, ‘dot’, ‘revive’, ‘fortune’],
[‘mobile’, ‘rack’, ‘mobile’, ‘phone’, ‘celebrate’, ‘anniversary’, ‘weekend’, ‘mobile’, ‘phone’, ‘call’, ‘vodafone’, ‘network’, ‘veteran’, ‘day’, ‘mobile’, ‘phone’, ‘integral’, ‘part’, ‘modern’, ‘life’, ‘briton’, ‘handset’, ‘mobile’, ‘popular’, ‘handset’, ‘phone’, ‘rarely’, ‘call’, ‘portable’, ‘phone’, ‘commercial’, ‘mobile’, ‘service’, ‘launch’, ‘rest’, ‘world’, ‘set’, ‘network’, ‘call’, ‘walk’, ‘call’, ‘office’, ‘house’, ‘day’, ‘vodafone’, ‘firm’, ‘mobile’, ‘network’, ‘launch’, ‘service’, ‘spokesman’, ‘phone’, ‘launch’, ‘size’, ‘cost’, ‘battery’, ‘life’, ‘minute’, ‘hugely’, ‘popular’, ‘mid’, ‘status’, ‘symbol’, ‘young’, ‘business’, ‘fact’, ‘phone’, ‘radio’, ‘signal’, ‘communicate’, ‘easy’, ‘rack’, ‘customer’, ‘month’, ‘easy’, ‘forget’, ‘put’, ‘bid’, ‘document’, ‘forecast’, ‘total’, ‘market’, ‘forecast’, ‘vodafone’, ‘customer’, ‘vodafone’, ‘mobile’, ‘phone’, ‘operator’, ‘launch’, ‘launch’, ‘newcomer’, ‘operate’, ‘mobile’, ‘network’, ‘operator’, ‘technology’, ‘spectrum’, ‘phone’, ‘retire’, ‘call’, ‘global’, ‘system’, ‘mobile’, ‘widely’, ‘phone’, ‘technology’, ‘planet’, ‘call’, ‘digital’, ‘technology’, ‘introduce’, ‘thing’, ‘text’, ‘mobile’, ‘popular’],
[‘launch’, ‘reconstruction’, ‘drive’, ‘appeal’, ‘peace’, ‘national’, ‘unity’, ‘important’, ‘find’, ‘solution’, ‘internal’, ‘conflict’, ‘damage’, ‘tsunami’, ‘cut’, ‘percentage’, ‘point’, ‘economic’, ‘growth’, ‘estimate’, ‘wave’, ‘leave’, ‘physical’, ‘damage’, ‘equal’, ‘economy’, ‘separately’, ‘lose’, ‘call’, ‘action’, ‘create’, ‘job’, ‘attend’, ‘ceremony’, ‘southern’, ‘town’, ‘join’, ‘government’, ‘opposition’, ‘politician’, ‘lay’, ‘foundation’, ‘stone’, ‘housing’, ‘project’, ‘intend’, ‘provide’, ‘home’, ‘tsunami’, ‘call’, ‘tragedy’, ‘start’, ‘beginning’, ‘rebuild’, ‘nation’, ‘country’, ‘natural’, ‘resource’, ‘fully’, ‘fight’, ‘add’, ‘due’, ‘arrive’, ‘revive’, ‘peace’, ‘talk’, ‘decade’, ‘long’, ‘conflict’, ‘government’, ‘force’, ‘tiger’, ‘separate’, ‘state’, ‘country’, ‘reconstruction’, ‘effort’, ‘hamper’, ‘tension’, ‘side’, ‘authority’, ‘initial’, ‘estimate’, ‘put’, ‘physical’, ‘damage’, ‘add’, ‘implication’, ‘economy’, ‘wide’, ‘broad’, ‘impact’, ‘substantial’, ‘detail’, ‘difficult’, ‘assess’, ‘early’, ‘stage’, ‘growth’, ‘inflation’, ‘balance’, ‘payment’, ‘foreign’, ‘exchange’, ‘reserve’, ‘expect’, ‘show’, ‘effect’, ‘lose’, ‘business’, ‘reconstruction’, ‘cost’, ‘industry’, ‘agricultural’, ‘production’, ‘affect’, ‘tourism’, ‘suffer’, ‘short’, ‘term’, ‘report’, ‘estimate’, ‘lose’, ‘job’, ‘industry’, ‘earning’, ‘tourism’, ‘expect’, ‘low’, ‘economic’, ‘growth’, ‘expect’, ‘previously’, ‘forecast’, ‘inflation’, ‘climb’, ‘compare’, ‘previous’, ‘estimate’, ‘major’, ‘export’, ‘suffer’, ‘expect’, ‘reconstruction’, ‘effort’, ‘require’, ‘high’, ‘import’, ‘damage’, ‘balance’, ‘payment’, ‘foreign’, ‘exchange’, ‘reserve’, ‘hard’, ‘press’, ‘international’, ‘reserve’, ‘pre’, ‘tsunami’, ‘level’, ‘total’, ‘month’, ‘worth’, ‘import’, ‘week’, ‘approve’, ‘request’, ‘freeze’, ‘loan’, ‘repayment’],
[‘buy’, ‘giant’, ‘profit’, ‘soar’, ‘acquisition’, ‘big’, ‘firm’, ‘tax’, ‘profit’, ‘rise’, ‘expect’, ‘solid’, ‘growth’, ‘performance’, ‘sale’, ‘firm’, ‘world’, ‘big’, ‘volume’, ‘buy’, ‘acquisition’, ‘sale’, ‘volume’, ‘grow’, ‘month’, ‘sale’, ‘account’, ‘increase’, ‘sell’, ‘volume’, ‘big’, ‘term’, ‘sale’, ‘continue’, ‘demand’, ‘product’, ‘south’, ‘american’, ‘market’, ‘brazilian’, ‘arm’, ‘popular’, ‘expect’, ‘boost’, ‘turnover’, ‘business’, ‘analyst’, ‘strong’, ‘performance’, ‘boost’, ‘share’, ‘market’, ‘end’, ‘report’, ‘contrast’, ‘volume’, ‘sale’, ‘fall’, ‘central’, ‘european’, ‘sale’, ‘rise’, ‘net’, ‘profit’]]

Это хорошо; каждый документ представляет собой предварительно обработанный список токенов, поэтому здесь нет необходимости проводить какую-либо предварительную обработку.

В OCTIS есть восемь встроенных тематических моделей:

(Обязательно укажите правильный документ, если вы реализуете одну из моделей)

Теперь давайте обучим модель NeuralLDA с этими данными:

from octis.models.NeuralLDA import NeuralLDA

Аналогичным образом можно импортировать и другие тематические модели, заменив «NeuralLDA» на имя из таблицы выше (обратите внимание, что «ProdLda» должно быть «ProdLDA»).

Инициализируем модель:

model = NeuralLDA(num_topics=20)

Все разные тематические модели содержат «num_topics». Остальные аргументы различаются в зависимости от модели и могут быть найдены на странице реализации. Однако проверка исходного кода позволяет быстрее найти аргументы:

import inspect
print(inspect.getsource(NeuralLDA))
>>> class NeuralLDA(AVITM):
def __init__(self, num_topics=10, activation=’softplus’, dropout=0.2, learn_priors=True, batch_size=64, lr=2e-3,
momentum=0.99, solver=’adam’, num_epochs=100, reduce_on_plateau=False, prior_mean=0.0,
prior_variance=None, num_layers=2, num_neurons=100, num_samples=10, use_partitions=True):
…

Аргументы в конструкторе можно задать вручную. В данном случае это:

  • num_topics
  • activation
  • dropout
  • learn_priors
  • batch_size
  • lr
  • momentum
  • solver
  • num_epochs
  • reduce_on_plateau
  • prior_mean
  • prior_variance
  • num_layers
  • num_neurons
  • num_samples
  • use_partition

А пока мы просто оставим настройки по умолчанию и установим num_topics = 20:

model = NeuralLDA(num_topics=20)
trained_model = model.train_model(dataset)
Now, you should see something like:
Epoch: [1/100] Samples: [1557/155700] Train Loss: 987.1886277195729 Time: 0:00:00.352704
Epoch: [1/100] Samples: [334/33400] Validation Loss: 982.9130479275823 Time: 0:00:00.020085
Epoch: [2/100] Samples: [3114/155700] Train Loss: 990.8275228805395 Time: 0:00:00.362417
Epoch: [2/100] Samples: [334/33400] Validation Loss: 982.0897677301647 Time: 0:00:00.010114
Epoch: [3/100] Samples: [4671/155700] Train Loss: 981.4996826328677 Time: 0:00:00.362483
Epoch: [3/100] Samples: [334/33400] Validation Loss: 965.4536162050898 Time: 0:00:00.010038

Обучаемая_модель - это словарь со следующими ключами:

print(trained_model.keys())
>>> dict_keys([‘topics’, ‘topic-document-matrix’, ‘topic-word-matrix’, ‘test-topic-document-matrix’])

Ключи следующие:

  1. themes: список тем Word.
  2. topic-word-matrix: распределение слов словаря для каждой темы (размеры: | количество тем | x | словарь |)
  3. topic-document-matrix: распределение тем для каждого документа учебного набора (размеры: | количество тем | x | учебные документы |)
  4. test-document-topic-matrix: распределение тем для каждого документа набора тестирования (размеры: | количество тем | x | тестовые документы |)

Первый ключ topics состоит из списка с n словами с наибольшей вероятностью для каждой темы из матрицы слов-тем.

Посмотрим, что это:

for topic in trained_model[‘topics’]:
    print(“ “.join(topic))
>>> claim chief meet budget official talk cut raise future economic
win side match final chance team season half great goal
company market sale month share expect rise fall growth report
charge competition link victim ago injury anti tragedy decision miss
government plan party add election public give claim week tory
game show give big play add back week put find
company find user firm technology mobile service phone accord information
case evidence order trial concern court common law clear power
enjoy tragedy rest carry navigate motion admit date opener technological
choose tragedy due motion navigate involve manage suffer stiff technological
film good top award star director movie chance performance career
rival reveal drug short range break challenge battle focus fourth
tragedy position seller navigate squeeze motion rare flanker overwhelming technological
include follow number hit man release hold place record band
tragedy navigate seller earn join escape squeeze opener adoption technological

Обычно согласованность используется для оценки качества тем. Давайте также проверим согласованность этой модели:

from octis.evaluation_metrics.coherence_metrics import Coherence

Среди различных мер согласованности c_v имеет наибольшую корреляцию с человеческой интерпретацией.

cv = Coherence(texts=dataset.get_corpus(),topk=10, measure=’c_v’)
print(‘Coherence: ‘ + str(cv.score(trained_model)))
>>> Coherence: 0.4963712149432245

(В отличие от типичной нотации моделирования тем, «topk» указывает количество слов, которые нужно включить в тему, а не количество тем. Поскольку наша тематическая модель содержит десять слов на тему, «topk» не может превышать 10).

Кроме того, OCTIS также может рассчитывать так называемый «показатель разнообразия», который представляет собой процент уникальных слов в теме. Этот балл является еще одним показателем качества подготовленных тем. Если уникальных слов не так много, значит, многие темы похожи и не имеют большого смысла.

from octis.evaluation_metrics.diversity_metrics import TopicDiversity
diversity = TopicDiversity(topk=10)
print(“Diversity score: “+str(diversity_score))
>>> Diversity score: 0.8533333333333334

И согласованность, и разнообразие в первую очередь интересны для сравнения тем различных тематических моделей. В следующем блоге я покажу, как сравнивать темы.