机器学习实战(一):Document clustering 文档聚类

简介: 文档聚类是指根据文档的文本和语义背景将其归入不同的组别。它是一种无监督的技术,因为我们没有文件的标签,它在信息检索和搜索引擎中得到了应用。

3607bb7ab9874e2f80f8a10584c2b7cf.png


1. 简介


 文档聚类是指根据文档的文本和语义背景将其归入不同的组别。它是一种无监督的技术,因为我们没有文件的标签,它在信息检索和搜索引擎中得到了应用。


 为了根据文档的内容进行分类,我决定使用K-手段算法。由于项目是没有标签的,这显然是一个无监督的学习问题,最好的解决方案之一应该是K-Means。当然,我们可以使用不同的算法,如高斯混合模型,甚至深度学习方法,如自动编码器。我将使用python与Jupyter笔记本,将代码和结果与文档结合起来。


 我在Anaconda环境下开发代码,并使用了以下依赖:


  • Pandas 库用于数据处理


  • Sklearn库用于机器学习和预处理


  • Matplotlib 库用于绘图


  • Ntlk库用于自然语言算法


  • BeautifulSoup库用于从 xml 文件中解析文本并删除类别


2.数据解析


 函数parseXML使用xml.etree.ElementTree来解析数据。我决定只使用项目的标题和描述来进行聚类,这与语义学最相关。由于描述不是原始文本,我们用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
#remove items with short 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


3. 符号化和词根化


 下一步是将文本标记为单词,删除任何形态词缀,并删除冠词和介词等常用词。这可以通过ntlk的内置功能来完成。最后,我们得到两个不同的词汇表(一个标记化和词干化,一个只有标记化),我们将它们合并到一个pandas数据框架中。


def tokenize_and_stem(text):
    #tokenize
    tokens = [word for sent in nltk.sent_tokenize(text) for word in nltk.word_tokenize(sent)]
    filtered_tokens = []
    #keep only letters
    for token in tokens:
        if re.search('[a-zA-Z]', token):
            filtered_tokens.append(token)
    #stemming
    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


# nltk's English stopwords and stemmer
stemmer = SnowballStemmer("english")
#create steam and tokenized voucabularies
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


4. 词向量化


 在我们将数据加载到K-手段算法之前,必须对其进行向量化。最流行的技术是Tdidf向量器,它根据文档中的单词频率创建一个矩阵,这就是我们要使用的技术。值得一提的是,作为未来的工作,word2vec和doc2vec可能会更有效地表示项目之间的关系。


#Tf-idf
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()
#calculate the distance matrix . I will use them in the visualization of the cluster.
dist = 1 - cosine_similarity(tfidf_matrix)


Td idf Matrix shape:  (1130, 74)


5.K means


 实际的聚类发生在这里,K means在Td-idf矩阵的基础上产生5个聚类。我们可以很容易地预测,这将不是一个最佳的解决方案,因为它只考虑到了文件中每个词的频率。


num_clusters = 5
km = KMeans(n_clusters=num_clusters)
km.fit(tfidf_matrix)
clusters = km.labels_.tolist()


 为了展示集群,我创建了一个由集群索引的pandas Dataframe。每个聚类的前6个词呈现在下面。我们注意到,这个聚类远非完美,因为有些词在一个以上的聚类中。另外,集群的语义内容之间也没有明确的区别。我们可以很容易地看到,与工作有关的词汇包括在多个聚类中。


items = { 'title': titles, 'description': descriptions}
frame = pd.DataFrame(items, index = [clusters] , columns = [ 'title','cluster'])
print("Top terms per cluster:")
# sort cluster centers by proximity to centroid
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]:  # replace 6 with n words per cluster
        print(' %s' % vocab_frame.ix[terms[ind].split(' ')].values.tolist()[0][0], end=',')
    print()
    #print("Cluster %d titles:" % i, end='')
    #for title in frame.ix[i]['title'].values.tolist():
       #print(' %s,' % title, end='')


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,


6.绘图


 为了实现聚类的可视化,我们应该首先降低其维度。我们用sklearn.manifold库中的t-SNE(t-Distributed Stochastic Neighbor Embedding)来实现。另一种方法是使用PCA或MDS(Multi-Demiensional Scaling)。


 绘图是用matplotlib库完成的。


import os  # for os.path.basename
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)
# dist is the distance matrix
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)
#we do not present the tiles of items to not make the graph overwhelming
#for i in range(len(df)):
    #ax.text(df.ix[i]['x'], df.ix[i]['y'], df.ix[i]['title'], size=4)
plt.show()


93967ef823b34f8bb7fa692db76a0c79.png


 我们可以发现结果并不像我们最初想象的那样糟糕。虽然有一些部分的重叠,但各组是相当有区别的。然而,毫无疑问,我们可以进一步优化它们。


 我们应该注意,只有几个字的项目没有在图中显示出来。我还注意到,有一些项目是用不同于英语的语言写的。我们目前没有处理它们,因此,它们的分类实际上是随机的。图中有一些错位的点。


 此外,在数据清理和预处理方面还有很多工作要做。一种方法是优化tdidf矢量化的参数,使用doc2vec进行矢量化。或者我们可以使用另一种技术,如亲和传播、频谱聚类或最近的方法,如HDBSCAN和变异自动编码器。

目录
相关文章
|
5月前
|
机器学习/深度学习 存储 运维
机器学习异常检测实战:用Isolation Forest快速构建无标签异常检测系统
本研究通过实验演示了异常标记如何逐步完善异常检测方案和主要分类模型在欺诈检测中的应用。实验结果表明,Isolation Forest作为一个强大的异常检测模型,无需显式建模正常模式即可有效工作,在处理未见风险事件方面具有显著优势。
427 46
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
1154 6
|
8月前
|
机器学习/深度学习 数据可视化 TensorFlow
Python 高级编程与实战:深入理解数据科学与机器学习
本文深入探讨了Python在数据科学与机器学习中的应用,介绍了pandas、numpy、matplotlib等数据科学工具,以及scikit-learn、tensorflow、keras等机器学习库。通过实战项目,如数据可视化和鸢尾花数据集分类,帮助读者掌握这些技术。最后提供了进一步学习资源,助力提升Python编程技能。
|
8月前
|
机器学习/深度学习 人工智能 Java
Java机器学习实战:基于DJL框架的手写数字识别全解析
在人工智能蓬勃发展的今天,Python凭借丰富的生态库(如TensorFlow、PyTorch)成为AI开发的首选语言。但Java作为企业级应用的基石,其在生产环境部署、性能优化和工程化方面的优势不容忽视。DJL(Deep Java Library)的出现完美填补了Java在深度学习领域的空白,它提供了一套统一的API,允许开发者无缝对接主流深度学习框架,将AI模型高效部署到Java生态中。本文将通过手写数字识别的完整流程,深入解析DJL框架的核心机制与应用实践。
514 3
|
8月前
|
机器学习/深度学习 数据可视化 算法
Python 高级编程与实战:深入理解数据科学与机器学习
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化和调试技巧。本文将深入探讨 Python 在数据科学和机器学习中的应用,并通过实战项目帮助你掌握这些技术。
|
9月前
|
数据可视化 API 开发者
R1类模型推理能力评测手把手实战
R1类模型推理能力评测手把手实战
253 2
|
9月前
|
人工智能 自然语言处理 网络安全
基于阿里云 Milvus + DeepSeek + PAI LangStudio 的低成本高精度 RAG 实战
阿里云向量检索服务Milvus版是一款全托管向量检索引擎,并确保与开源Milvus的完全兼容性,支持无缝迁移。它在开源版本的基础上增强了可扩展性,能提供大规模AI向量数据的相似性检索服务。凭借其开箱即用的特性、灵活的扩展能力和全链路监控告警,Milvus云服务成为多样化AI应用场景的理想选择,包括多模态搜索、检索增强生成(RAG)、搜索推荐、内容风险识别等。您还可以利用开源的Attu工具进行可视化操作,进一步促进应用的快速开发和部署。
|
9月前
|
数据可视化 API 开发者
R1类模型推理能力评测手把手实战
随着DeepSeek-R1模型的广泛应用,越来越多的开发者开始尝试复现类似的模型,以提升其推理能力。
761 2
|
9月前
|
数据可视化 API 开发者
R1类模型推理能力评测手把手实战
随着DeepSeek-R1模型的广泛应用,越来越多的开发者开始尝试复现类似的模型,以提升其推理能力。
647 3
|
机器学习/深度学习 人工智能 TensorFlow
基于TensorFlow的深度学习模型训练与优化实战
基于TensorFlow的深度学习模型训练与优化实战
542 3