网页聚类
网页聚类
目标
爬取网页内容,提取其关键词,并进行聚类。
网页爬取
数据来源为央视新闻网,计划先提取本页面链接,然后根据链接请求页面内容。但是模拟发包请求数据后发现,接受到的内容中并没有包含想要的内容。于是查看其发送数据,发现传入数据的接口,其中包含几十条数据,里面包含网页的链接,直接复制数据,保存在文件中,数据部分截图如下:
所以直接提取本文件的链接,请求链接内容,爬取网页内容,下图为爬取网页新闻内容,共67条。
分词并去除停用词
读取内容使发现,存在‘\u3000,\u200d’不可见字符,先将其替换为空;
接着去除数字,字母等符号
然后使用jieba库对文本进行分词
分词后,使用https://github.com/goto456/stopwords,提供的中文停用词表,对分词后的内容进一步去除。
使用tf-idf提取特征
Tf-idf的基于的思想为:一个词越能代表一个文章,则其在该文章中出现的次数越多,同时在别的文章中出现的越少。其计算公式为,以A词为例:
最后该词A的tf-idf值为tf×idf。
所以一个文档最后可以表示为n维的向量,n为词表的数量,即所有文档的所有不重复词的数量。每一维值为文档中包含的词的tf-idf值,文档在词表中不存在的词的位置处值为0。在本程序中只保留500个特征,即500维
提取关键词
利用tf-idf值提取关键词,即选取tf-idf值最大的词作为关键词,这里对tf-idf排序后,选取最大的前三个词作为关键词
如:一篇关于职教高考的新闻提取的三个关键词如下,效果还不错
[('高考', 0.6920650673965045), ('职教', 0.4898802855129175), ('院校', 0.26144680323867947)]
特征降维
由于只有67条数据,为了保证聚类效果,对特征进一步降维,这里采用主成分分析法PCA,将维数降到10维。
PCA其实使用了奇异值分解SVD进行降维,将原TF-IDF矩阵W(词-文档向量)分解为3个简单的矩阵,其中m为词表数,n为文档数,p为主题数(类别)
对U,S,V只取前几列,再相乘后重构原矩阵,这个矩阵就包含了隐性语义,且减少了噪音,降维后,特征如下所示:
[-1.07769197e-01 -2.87990407e-03 -7.73572728e-02 -3.84999819e-02
-6.19093644e-02 2.70522170e-02 2.15039165e-02 -1.93054298e-01
-2.52937840e-01 -2.02132253e-01]
使用Birch算法聚类
构造CF树,树中每个节点包含CF特征。N为数据数量,LS为每个数据特征的和,SS为每个数据特征的平方和
算法含有两个约束:分支因子:限制节点中子聚类的数量。阈值:限制新数据与子聚类的距离。
每次计算新数据加入到各个子聚类的簇直径,选择直径最小的加入。如果加入后,新的子聚类获得的子聚类的半径大于阈值的平方,则该数据重新成为新的子聚类。如子聚类的数量大于分支因子,则取两个最远的子聚类,并根据这些子聚类之间的距离将子聚类分为两组。
结果分析
以下为分类结果标签,可以看到总共聚类成6类:
[0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 3, 3, 4, 2, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 2, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0]
以下为聚类结果图,可以看出,1类为垃圾分类相关,2类为肺炎疫情相关,3类与美国相关,4类与警情相关,5类与交通相关,分类效果还可。
但是,0类包含了大量数据,基本为国内政策新闻,效果不太好,其实还可以进一步细分。
代码
import re
import jieba
import requests
from bs4 import BeautifulSoup
import json
import time
from tqdm import tqdm
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn import decomposition
from sklearn.cluster import Birch
#提取文件中链接
my_link=[]
with open(r'C:\Users\DELL\Desktop\my.json',encoding='utf-8') as f:
data=json.load(f)
for i in data['data']['list']:
my_link.append(i['url'])
#爬取内容
for i in tqdm(my_link):
time.sleep(5)
url = i
# 请求页面
try:
r = requests.get(url)
r.encoding = r.apparent_encoding
html = BeautifulSoup(r.text, 'html.parser')
content = html.find('div', {'class': 'content_area'})
text = ''
for i in content.find_all('p'):
text = text + i.getText()
with open('C:/Users/DELL/Desktop/mynews.txt','a',encoding='utf-8') as fw:
fw.write(text.replace('\n',' ')+'\n')
except:
print(i)
# 分词并去除停用词
def remove(text):
remove_chars = '[0-9a-zA-Z’!"#$%&\'()*+,-./:;<=>?@,。?★、…【】《》?“”‘’![\\]^_`{|}~]+'
return re.sub(remove_chars, '', text)
words = []
with open(r'C:\Users\DELL\Downloads\stopwords-master\stopwords-master\cn_stopwords.txt',encoding='utf-8') as f2:
stopwords=f2.read()
with open('C:/Users/DELL/Desktop/mynews.txt',encoding='utf-8') as f:
for i in f.readlines():
word_str = ''
content=i.replace("\u3000", "")
content = content.replace("\u200d", "")
content=remove(content)
text=jieba.lcut(content)
for word in text:
if word not in stopwords:
word_str=word_str+' '+word
words.append(word_str)
#计算tfidf,只保留500个特征
VT=TfidfVectorizer(token_pattern=r"(?u)\b\w+\b",max_features=500)
tfidf=VT.fit_transform(words)
#提取关键词,根据tfidf排序,取前三个
key_word=[]
for text in tfidf.toarray():
text=dict(zip(VT.get_feature_names_out(),text))
key_word.append(sorted(text.items(),key = lambda kv:(kv[1], kv[0]),reverse=True)[:3])
#利用pca降维,保留10个特征
pca = decomposition.PCA(n_components=10)
pca_text=pca.fit_transform(tfidf.toarray())
print(pca_text)
#利用birch算法聚类并展示
brc=Birch(n_clusters=None)
brc.fit(pca_text)
label=list(brc.predict(pca_text))
print(label)
for i in set(label):
for j in [j for j,x in enumerate(label) if x==i]:
print(i,key_word[j],words[j])