Home Искусственный интеллект Кластеризация документов | ИИ Лето | DeepTech

Кластеризация документов | ИИ Лето | DeepTech

0
Кластеризация документов |  ИИ Лето
 | DeepTech

Кластеризация документов — это задача классификации документов по разным группам на основе их текстового и семантического контекста. Это неконтролируемый метод, поскольку у нас нет меток для документов, и он применяется в информационном поиске и поисковых системах.

Давайте начнем…

Чтобы классифицировать документы на основе их содержания, я решил использовать алгоритм К-средних. Из-за того, что элементы не помечены, это явно проблема обучения без учителя, и одним из лучших решений должно быть K-Means. Конечно, мы можем использовать другой алгоритм, например смешанные модели Гаусса, или даже методы глубокого обучения, такие как автоэнкодеры. Я буду использовать python с блокнотом Jupyter, чтобы объединить код и результаты с документацией.

Я разрабатываю код в Анаконда среду, и я использую следующие зависимости:

Панды для передачи данных

Склеарн для машинного обучения и предварительной обработки

Матплотлиб для построения

нтлк для алгоритмов естественного языка

КрасивыйСуп разобрать текст из xml файла и избавиться от категорий

Анализ данных

Функция parseXML использует xml.etree.ElementTree для анализа данных. Я решил использовать для кластеризации только название и описание элементов, наиболее релевантных семасиологии. Из-за того, что описание не является raw tex, мы извлекаем текст библиотекой BeautifulSoup, как я уже упоминал. Также мы отбрасываем элементы с очень маленьким описанием, потому что они влияют на окончательную кластеризацию. Можно считать, что все они принадлежат дополнительному кластеру. Конечно, есть способы их включить, но я пока ими не пользуюсь.

import xml.etree.ElementTree as ET

import pandas as pd

import nltk

from sklearn.cluster import KMeans

from sklearn.externals import joblib

from sklearn.feature_extraction.text import TfidfVectorizer

from sklearn.metrics.pairwise import cosine_similarity

nltk.download('punkt')

from bs4 import BeautifulSoup

from nltk import SnowballStemmer

import re

def parseXML(xmlfile):

tree = ET.parse(xmlfile)

root = tree.getroot()

titles=()

descriptions=()

for item in root.findall('./channel/item'):

for child in item:

if(child.tag=='title' ):

titles.append(child.text)

if (child.tag == 'description' ):

soup = BeautifulSoup(str(child.text).encode('utf8','ignore'), "lxml")

strtext=soup.text.replace(u'\xa0', u' ').replace('\n',' ')

descriptions.append(strtext)

return titles,descriptions

bef_titles,bef_descriptions = parseXML('data.source.rss-feeds.xml')

print('Count of items before dropping:' ,len(bef_titles))

titles=()

descriptions=()

for i in range(len(bef_titles)):

if ( len(bef_descriptions(i)) > 500):

titles.append(bef_titles(i))

descriptions.append(bef_descriptions(i))

print('Count of items after:' ,len(titles))

(nltk_data) Downloading package punkt to

(nltk_data) C:\Users\sergi\AppData\Roaming\nltk_data...

(nltk_data) Package punkt is already up-to-date!

Count of items before dropping: 1662

Count of items after: 1130

Токенизация и стемминг

Следующим шагом является разбиение текста на слова, удаление всех морфологических аффиксов и удаление общих слов, таких как артикли и предлоги. Это можно сделать с помощью встроенных функций ntlk. В конце концов, мы получаем два разных словаря (один токенизированный и базовый и один только токенизированный), и мы объединяем их в кадр данных pandas.

def tokenize_and_stem(text):

tokens = (word for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent))

filtered_tokens = ()

for token in tokens:

if re.search('(a-zA-Z)', token):

filtered_tokens.append(token)

stems = (stemmer.stem(t) for t in filtered_tokens)

return stems

def tokenize_only(text):

tokens = (word.lower() for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent))

filtered_tokens = ()

for token in tokens:

if re.search('(a-zA-Z)', token):

filtered_tokens.append(token)

return filtered_tokens

stemmer = SnowballStemmer("english")

totalvocab_stemmed = ()

totalvocab_tokenized = ()

for i in descriptions:

allwords_stemmed = tokenize_and_stem(i)

totalvocab_stemmed.extend(allwords_stemmed)

allwords_tokenized = tokenize_only(i)

totalvocab_tokenized.extend(allwords_tokenized)

vocab_frame = pd.DataFrame({'words': totalvocab_tokenized}, index=totalvocab_stemmed)

print('there are ' + str(vocab_frame.shape(0)) + ' items in vocab_frame')

there are 481437 items in vocab_frame

Векторизация и стемминг

Прежде чем мы загрузим данные в алгоритм K-средних, необходимо их векторизовать. Самый популярный метод — векторизатор Tdidf, который создает матрицу на основе частоты слов в документах, и именно его мы собираемся использовать. По сути, это показывает, насколько важно слово для документа. Стоит упомянуть об этом в качестве будущей работы. слово2век и doc2vec может быть гораздо более эффективным для представления отношений между элементами.

tfidf_vectorizer = TfidfVectorizer(max_df=0.8, max_features=200000,min_df=0.2, stop_words='english',

use_idf=True, tokenizer=tokenize_and_stem, ngram_range=(1,3))

tfidf_matrix = tfidf_vectorizer.fit_transform(descriptions)

print('Td idf Matrix shape: ',tfidf_matrix.shape)

terms = tfidf_vectorizer.get_feature_names()

dist = 1 - cosine_similarity(tfidf_matrix)

Td idf Matrix shape: (1130, 74)

К означает

Здесь происходит фактическая кластеризация, где K означает создание 5 кластеров на основе матрицы Td-idf. Мы можем легко предсказать, что это не будет оптимальным решением, поскольку оно учитывает только частоту каждого слова в документе.

num_clusters = 5

km = KMeans(n_clusters=num_clusters)

km.fit(tfidf_matrix)

clusters = km.labels_.tolist()

Чтобы представить кластер, я создаю кадр данных pandas, индексированный кластерами. Ниже представлены первые 6 слов каждого кластера. Мы замечаем, что кластеризация далека от совершенства, поскольку некоторые слова входят более чем в одну группу. Также нет четкого разграничения смыслового содержания кластеров. Мы легко можем видеть, что термины, связанные с работой, включают более одного кластера.

items = { 'title': titles, 'description': descriptions}

frame = pd.DataFrame(items, index = (clusters) , columns = ( 'title','cluster'))

print("Top terms per cluster:")

order_centroids = km.cluster_centers_.argsort()(:, ::-1)

for i in range(num_clusters):

print("Cluster %d words:" % i, end='')

for ind in order_centroids(i, :6):

print(' %s' % vocab_frame.ix(terms(ind).split(' ')).values.tolist()(0)(0), end=',')

print()

Top terms per cluster:

Cluster 0 words: labour, employability, european, social, work, eu,

Cluster 1 words: occupational, sectors, skill, employability, services, workers,

Cluster 2 words: skill, job, labour, develop, market, cedefop,

Cluster 3 words: education, training, learning, vocational, education, cedefop,

Cluster 4 words: rates, unemployment, area, employability, increasingly, stated,

Визуализация

Чтобы визуализировать кластеризацию, мы должны сначала уменьшить их размерность. Мы достигли этого с помощью t-SNE (t-Distributed Stochastic Neighbor Embedding) из библиотеки sklearn.manifold. Другой способ использовать СПС или многомерное масштабирование (MDS).

Графика выполняется с помощью библиотеки matplotlib.

import os

import matplotlib.pyplot as plt

import matplotlib as mpl

from sklearn.manifold import TSNE

tsne = TSNE(n_components=2, verbose=1, perplexity=40, n_iter=300)

pos = tsne.fit_transform(dist)

xs, ys = pos(:, 0), pos(:, 1)

cluster_colors = {0: '#1b9e77', 1: '#d95f02', 2: '#7570b3', 3: '#e7298a', 4: '#66a61e'}

cluster_names = {0: 'A',1: 'B', 2: 'C', 3: 'D', 4: 'E'}

(t-SNE) Computing pairwise distances...

(t-SNE) Computing 121 nearest neighbors...

(t-SNE) Computed conditional probabilities for sample 1000 / 1130

(t-SNE) Computed conditional probabilities for sample 1130 / 1130

(t-SNE) Mean sigma: 1.785805

(t-SNE) KL divergence after 100 iterations with early exaggeration: 0.947952

(t-SNE) Error after 125 iterations: 0.947952

%matplotlib inline

df = pd.DataFrame(dict(x=xs, y=ys, label=clusters, title=titles))

groups = df.groupby('label')

fig, ax = plt.subplots(figsize=(16,8) )

for name, group in groups:

ax.plot(group.x, group.y, marker='o', linestyle='', ms=12,

label=cluster_names(name), color=cluster_colors(name), mec='none')

ax.legend(numpoints=1)

plt.show()


Результат кластеризации

Мы видим, что результаты не так плохи, как мы думали изначально. Хотя есть некоторое частичное совпадение, группы весьма различаются. Однако нет никаких сомнений в том, что мы можем оптимизировать их гораздо дальше.

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

Кроме того, предстоит еще много работы по очистке и предварительной обработке данных.

Один из способов — оптимизировать параметры векторизации tdidf, используя doc2vec для векторизации. Или мы можем использовать другой метод, такой как Affinity Propagation, Spectra Clustering или более современные методы, такие как HDBSCAN и Вариационные автоэнкодерыкоторый я хотел бы развивать.

PS: Чтобы запустить код, вы можете сделать это прямо из jupyter, если установлены необходимые зависимости, или вы можете экспортировать его в виде файла .py и запустить с помощью ide или напрямую через консоль.

Книга «Глубокое обучение в производстве» 📖

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

Узнать больше

* Раскрытие информации: Обратите внимание, что некоторые из приведенных выше ссылок могут быть партнерскими ссылками, и без дополнительной оплаты для вас мы будем получать комиссию, если вы решите совершить покупку после перехода по ссылке.

LEAVE A REPLY

Please enter your comment!
Please enter your name here