网页聚类

网页聚类

目标

爬取网页内容,提取其关键词,并进行聚类。

网页爬取

数据来源为央视新闻网,计划先提取本页面链接,然后根据链接请求页面内容。但是模拟发包请求数据后发现,接受到的内容中并没有包含想要的内容。于是查看其发送数据,发现传入数据的接口,其中包含几十条数据,里面包含网页的链接,直接复制数据,保存在文件中,数据部分截图如下:

所以直接提取本文件的链接,请求链接内容,爬取网页内容,下图为爬取网页新闻内容,共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])


posted @ 2022-02-18 17:33  启林O_o  阅读(226)  评论(0编辑  收藏  举报