机器学习 K-Means 实现文本聚类 2021-10-30

人工智能总目录

1. 数据集信息

数据集在个人附件中,名为abcnews-date-text.csv。

import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.feature_extraction import text
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from nltk.tokenize import RegexpTokenizer
from nltk.stem.snowball import SnowballStemmer

# 读取数据集
data = pd.read_csv("abcnews-date-text.csv",error_bad_lines=False,usecols =["headline_text"])
data.head()
# 获取部分数据快速运行,你可以尝试修改使用的数据量查看后续的建模效果,不过注意使用的数据越多后续模型训练的时间越长
data = data.head(10000)  

# 打印数据信息
data.info()
# 删除重复行
data = data.drop_duplicates('headline_text')

2. 数据预处理

2.1 为向量化表示进行前处理

进行自然语言处理时,必须将单词转换为机器学习算法可以利用的向量。如果目标是对文本数据进行机器学习建模,例如电影评论或推文或其他任何内容,则需要将文本数据转换为数字。此过程称为“嵌入”或“向量化”。
进行向量化时,请务必记住,它不仅仅是将单个单词变成单个数字。单词可以转换为数字,整个文档就可以转换为向量。向量的维度往往不止一个,而且对于文本数据,向量通常是高维的。这是因为特征数据的每个维度将对应一个单词,而我们所处理的文档通常包含数千个单词。

2.2 TF-IDF

在信息检索中,tf–idf 或 TFIDF(term frequency–inverse document frequency)是一种数值统计,旨在反映单词对语料库中文档的重要性。在信息检索,文本挖掘和用户建模的搜索中,它通常用作加权因子。 tf-idf 值与单词在文档中出现的次数成正比,同时被单词在语料库中的出现频率所抵消,这有助于调整某些单词通常会更频繁出现的事实。 如今,tf-idf是最流行的术语加权方案之一。在数字图书馆领域,有83%的基于文本的推荐系统使用tf-idf。

搜索引擎经常使用tf–idf加权方案的变体作为在给定用户查询时对文档相关性进行评分和排名的主要工具。tf–idf可成功用于各种领域的停用词过滤,包括文本摘要和分类。

排名函数中最简单的是通过将每个查询词的tf–idf相加得出,许多更复杂的排名函数是此简单模型的变体。

punc = ['.', ',', '"', "'", '?', '!', ':', ';', '(', ')', '[', ']', '{', '}',"%"]
stop_words = text.ENGLISH_STOP_WORDS.union(punc)
desc = data['headline_text'].values
vectorizer = TfidfVectorizer(stop_words = stop_words)
# X 矩阵含义说明, 一行是对应输入的desc 文本的tf-idf 值,每一列与特征的单词对应vectorizer.get_feature_names(),0 说明 该desc 文本没有此特征词。
# fit 学习里面的参数, tfidf 里为统计词频与逆文档率,归一化为计算均值与方差
# transform 把学习到的参数用到数据中。
# fit_transform 实现这两步,得到了一个矩阵的结果。
X = vectorizer.fit_transform(desc)
word_features = vectorizer.get_feature_names()

2.3 Stemming

stemming 是将单词还原为词干(即词根形式)的过程。 词根形式不一定是单词本身,而是可以通过连接正确的后缀来生成单词。 例如,“fish”,“fishes”和“fishing”这几个词的词干都是“fish”,这是一个正确的单词。 另一方面,“study”,“studies”和“studying”一词源于“studi”,这不是一个正确的英语单词。

2.4 Tokenizing

Tokenization 将句子分解为单词和标点符号。

2.5 使用停用词、stemming 和自定义的 tokenizing 进行 TFIDF 向量化

# 设置停用词
punc = ['.', ',', '"', "'", '?', '!', ':', ';', '(', ')', '[', ']', '{', '}',"%"]
stop_words = text.ENGLISH_STOP_WORDS.union(punc)
# 处理词根的方法
stemmer = SnowballStemmer('english')
# 使用正则表达式匹配单词, 
tokenizer = RegexpTokenizer(r'[a-zA-Z\']+')

def tokenize(text):
	# 相当于对输入的字符串"aba decides against community broadcasting licence" 进行re.findall匹配
	# stemmer.stem 对每一个单词进行词根处理
    return [stemmer.stem(word) for word in tokenizer.tokenize(text.lower())]

# 使用最多1000特征,停用词及处理函数
vectorizer3 = TfidfVectorizer(stop_words = stop_words, tokenizer = tokenize, max_features = 1000)
# desc 是列表形式
desc = data['headline_text'].values
# 计算TF-IDF矩阵
X3 = vectorizer3.fit_transform(desc)
words = vectorizer3.get_feature_names()

3 K-Means 聚类

3.1 使用手肘法选择聚类簇的数量

随着聚类数k的增大,样本划分会更加的精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小,并且当k小于真实的簇类数时,由于k的增大会大幅增加每个簇的聚合程度,因此SSE的下降幅度会很大,而当k到达真实聚类数时,再增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系类似于手肘的形状,而这个肘部对应的k值就是数据的真实聚类数.因此这种方法被称为手肘法.

from sklearn.cluster import KMeans
wcss = []
for i in range(1,11):
    kmeans = KMeans(n_clusters=i,init='k-means++',max_iter=300,n_init=10,random_state=0)
    kmeans.fit(X3)
    wcss.append(kmeans.inertia_)
plt.plot(range(1,11),wcss)
plt.title('The Elbow Method')
plt.xlabel('Number of clusters')
plt.ylabel('WCSS')
plt.savefig('elbow.png')
plt.show()

由于可能产生多个肘点,所以有时候不得不通过反复试验来选择合适数量的簇。下面展示不同数量簇的结果,以找出合适数量的簇。

3.2 Clusters 等于 3

kmeans = KMeans(n_clusters = 3, n_init = 20, n_jobs = 1) # n_init(number of iterations for clsutering) n_jobs(number of cpu cores to use)
kmeans.fit(X3)
# We look at 3 the clusters generated by k-means.
# argsort 使用方法详见: https://numpy.org/doc/stable/reference/generated/numpy.argsort.html
common_words = kmeans.cluster_centers_.argsort()[:,-1:-26:-1]
for num, centroid in enumerate(common_words):
    print(str(num) + ' : ' + ', '.join(words[word] for word in centroid))

3.3 Clusters 等于 5

# 重复上面的做法,仅改变聚类簇的数量 (尝试将上述过程封装成一个函数,减少代码的重读性,方便传参调用)
kmeans = KMeans(n_clusters = 5, n_init = 20, n_jobs = 1)
kmeans.fit(X3)
# We look at 5 the clusters generated by k-means.
common_words = kmeans.cluster_centers_.argsort()[:,-1:-26:-1]
for num, centroid in enumerate(common_words):
    print(str(num) + ' : ' + ', '.join(words[word] for word in centroid))

3.4 Clusters 等于 6

优质参考内容:

  1. CountVectorizer与TfidfVectorizer https://blog.csdn.net/The_lastest/article/details/79093407
  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值