大数据行业应用-微博热点发现

1、实验描述

社交网络在社会热点话题等方面起着重要作用。如何高效迅速的处理海量的微博数据、快速非人工的发现当前的热点话题具有一定的挑战。和博客长文本相比很大的差异之处,微博形式主要以短文本为主。微博的语义相对而言更不易总结,很难快速发现隐含的热点话题。热点发现的研究涉及到计算语言学、人工智能、统计学、信息科学等多种学科,是自然语言处理应用领域的研究热点之一。该项目针对微博热点话题词进行整理排序,方便用户查看当前热点词条信息。首先对微博数据集的话题词提取,通过分词、过滤、聚类等技术排序出热点话题。

  • 实验时长:120分钟
  • 主要步骤:
    • 对微博数据获取与整合
    • 对采集到的数据预处理
    • 对数据进行中文分词
    • 选取特征词进行文本建模
    • 微博热点话题词抽取

2、实验环境

  • anaconda 版本:anaconda3
  • python 版本:python 3.6
  • 导入HanLP包、gensim包

3、相关技能

  • python3编程
  • 自然语言处理基本方法

4、相关知识点

  • 获取到的微博数据采集是json数据结构
  • 解析数据存储到Sql Server
  • 对问句进行分词,并去除停用词(HanLP)
  • 根据问题文本构建SVM向量空间模型
  • 余弦相识度计算
  • FAQ匹配数据库构建
  • TF-IDF关键词提取
  • Kmeans算法对微博信息文本进行文本聚类

5、实验步骤

6.1 数据准备,将API和网络爬虫结合采集到的数据解析后存储到Sql Server,数据中的微博相关信息,进行降噪处理,去除干扰信息之后对微博的短文本数据进行分词处理。最后将处理完成的数据整理存入excel文件“new_weibotext.xlsx”中,截取的部分数据如图所示。此文件已存放在工作目录中。

image-20240724092935140

6.2 右击桌面空白处,单击”打开终端“,如图所示。

image-20240724092955404

6.3 在命令提示符下输入

1
2
# cd
# jupyter-notebook --ip=0.0.0.0

如图所示,回车,进入Jupyter-Notebook。

image-20240724093043758

6.4 在打开的Jupyter Notebook中,单击”数据与程序代码”目录,进入后点击对应的章节目录,如图所示。

image-20240724093201102

6.5 单击“新建”,选择“Python3”,新建Python3文件,如图所示。

image-20240724093224348

6.6 在默认的第一个Cell里导入所用第三方库,分别是数据分析包pandas,科学计算基础包numpy,中文分词库jieba,记录日志模块logging,快速文本分类算法fasttext,多进程管理包multiprocessing中的cpu_count函数,matplotlib绘图模块,kMeans聚类算法,以及数据存储包pickle,os模块,渲染制作图云的wordcloud模块,输入代码以下代码。

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd
import numpy as np
import jieba
import re
import logging
import fasttext
from multiprocessing import cpu_count
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import pickle
import os
from wordcloud import WordCloud

image-20240724093709679

6.7 使用jieba.load_userdict(‘./data/uers_words.txt’)来载入自定义词典文档,如下所示。

1
jieba.load_userdict('./data/uers_words.txt')

6.8 编译正则表达式模式,返回一个对象patten,如下所示。

1
patten = re.compile('[\u4e00-\u9fa5]+')

6.9 定义data_clean函数,将图2所示的“stop_words.txt”中的数据去掉空格添加到stopword中,读取excel表“new_weibotext1.xlsx”,将文件“Text”赋给f,建立字典word_list,随后打开文件“cut_line.text”,之后逐行遍历传给f的文档,进入外层判断语句,运行程序。代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def data_clean():
stopword = [word.strip for word in open('./data/stop_words.txt','r',encoding='utf-8')]
file = pd.read_excel('./data/new_weibotext1.xlsx', engine='openpyxl')
# print(file.head(10))
f = file['Text']
word_dict = {}
with open('./data/cut_line.txt','w',encoding='utf-8') as fl:
for line in f:
words = patten.findall(str(line).strip())
word_list = [word for word in jieba.lcut(''.join(words))]
if word_list:
for word in word_list:
if word_dict.get(word,0):
word_dict[word] += 1
else:
word_dict[word] = 1
fl.write(' '.join(word_list)+'\n')

sort_word_count = sorted(word_dict.items(),key=lambda x:x[-1],reverse=True)
print(sort_word_count[:10])
data_clean()

6.10 若运行结果正确,会以字典的形式输出出现次数最多的前10个汉字跟它的出现次数。

同时按下Ctrl+Enter键,该Cell中的程序运行结果如图所示。

image-20240724104120730

6.11 在第四个Cell中,定义Word2Vec类,在类里面定义train_w2v方法,方法里面使用fasttext.train_unsupervised函数,为了学习词向量(向量表示),并且在学习开始时输出’Start training word vectors……’,保存好模型后print输出’Word vector train done!!!’。代码清单如下所示。

1
2
3
4
5
6
7
8
class Word2Vec:
def train_w2v(self,file):
print('Start training word vectors......')
w2vModel = fasttext.train_unsupervised(file, model='skipgram', epoch=100, lr=0.01,
dim=100, ws=5, word_ngrams=2,
bucket=2000000)
w2vModel.save_model('./model/word2vec_model_100.bin')
print('Word vector train done!!!')

6.12 定义load_model方法,内置加载模型函数,定义sentences_embedding私有方法,定义形状矩阵;代码清单如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def load_model(self,model_path):
w2v_model = fasttext.load_model(model_path)
return w2v_model
def sentences_embedding(self,line,model):
vector = np.zeros(100)
#print(line)
for word in line.split(' '):
#print(word)
try:
vector += model[word]
except:
pass
vector = vector / len(line.split(' '))
return list(vector)

6.13 定义file_embedding私有方法,循环逐一判断文件是否去除空格,并在循环判断语句中调用sentences_embedding方法。代码清单如下所示。

1
2
3
4
5
6
7
8
9
10
def file_embedding(self,file,model):
out_vector = []
for line in file:
#print(line)
if line.strip():
vector = self.sentences_embedding(line.strip(),model)
out_vector.append(vector)
else:
pass
return out_vector

6.14 在第四个Cell中,定义Similar类,在类里定义sentencssim私有方法跟vectorCosine私有方法,方法里进行数学运算。代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
class Similar:
def sentencs_sim(self,text1,text2):
# vector1 = vector1 / len(word_list1)
# vector2 = vector2 / len(word_list2)
return self.vectorCosine(text1,text2)
def vectorCosine(self,vector1,vector2):
cos1 = np.sum(vector1 * vector2)
cos21 = np.sqrt(sum(vector1 ** 2))
cos22 = np.sqrt(sum(vector2 ** 2))
similarity = cos1 / float(cos21 * cos22)
return similarity

6.15 在第五个Cell中,定义KMEANA类,在类里定义train私有方法,输入数据,用predict()方法进行预测、使用Kmeans算法的文本聚类。代码清单如下所示。

1
2
3
4
5
6
class KMEANA:
def train(self,data,n_clusters):
km = KMeans(n_clusters=n_clusters,n_init=n_clusters,tol=0.0001,init='k-means++') # 初始化
km.fit(data) # 拟合
km_pred = km.predict(data) # 预测
centers = km.cluster_centers_ # 质心

6.16 将倒排索引永久存储在“./model/kmeans_model.pkl”文件中,程序代码如下所示。

1
2
with open('./model/kmeans_model.pkl','wb') as f:
pickle.dump(km,f)

6.17 再用figure模块绘图,fig.add_subplot函数画子图,设置主题名称跟横纵坐标的名称。代码如下所示。

1
2
3
4
5
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.set_title('Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')

6.18 通过scatter函数定义散点图中点的大小,颜色,标记。最后以图片的格式显示绘图结果、保存图片。代码如下所示。

1
2
3
4
5
plt.scatter(np.array(data)[:, 1], np.array(data)[:, 0], c=km_pred,marker='.')
plt.scatter(centers[:, 1], centers[:, 0], c="r",marker='p',linewidths=5)
plt.show()
fig.savefig('./data/plot.png')
ax1.set_title('centers scatter Plot')

6.19 用同样的方法绘制出第二张图片。程序代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
plt.xlabel('X')
plt.ylabel('Y')
cValue = ['r', 'y', 'g', 'b', 'r', 'y', 'g', 'b', 'r', 'y', 'g', 'b','r', 'y', 'g', 'b','r', 'y', 'g', 'b']
plt.scatter(centers[:, 1], centers[:, 0], c=cValue, marker='p', linewidths=5)
plt.show()
result = {}
for text_idx, label_idx in enumerate(km_pred):
if label_idx not in result:
result[label_idx] = [text_idx]
else:
result[label_idx].append(text_idx)
return result,list(centers)

同时按下Ctrl+Enter键,该Cell中的程序运行结果如图所示。

image-20240724105008276

6.20 在下一个cell里,创建MODEL类,定义私有方法,用来判断文件是否存在。代码清单如下显示。

1
2
3
4
5
6
7
class MODEL:
def __init__(self,path,model_path):
self.file = self.read_file(path)
# print(list(self.file))
if not os.path.exists('./model/word2vec_model_100.bin'):
w2v.train_w2v(path)
self.w2v_model = w2v.load_model(model_path)

6.21 以只读方式打开文件并去除文档中的空格。代码如下所示。

1
2
3
4
5
def read_file(self,path):
file = open(path,'r',encoding='utf-8')
return [line.strip() for line in file if line.strip()]
def all_line(self):
return [line.strip() for line in self.file if line.strip()]

6.22 定义形状矩阵,统计已经训练过的文章后的余弦相似度。统计每个类别下,和聚类中心最近的topk个文本id集合,对列表进行排序。代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def sim_one_centers(self,ponits,center_vec):
'''
统计每个类别下,和聚类中心距离最近的topk个文本id集合
:param ponits: 给类别下的所有的文本id
:param center_vec: 聚类中心向量
:return: 与聚类中心距离最近的topk个文本id
'''
sentence_sim_dict = {}
print('该类别的集合:{}'.format(ponits))
# print(type(center_vec))
for i in ponits:
line = self.file[i]
line_vec = w2v.sentences_embedding(line,self.w2v_model)

# print(np.array(line_vec).shape)
# print(center_vec.shape)
cos = sim.vectorCosine(center_vec,np.array(line_vec))
sentence_sim_dict[i] = cos

top_line = sorted(sentence_sim_dict.items(),key=lambda x:x[1])[:int(len(ponits)*0.5)]
# print('top_line:{},数量为:{}'.format(top_line,len(top_line)))
# print(lines[top_line[0][0]])
return [item[0] for item in top_line]

6.23 统计几个聚类中心的距离,返回频次最高的topk个中心。代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def center_sim(self):
'''
统计几个聚类中心的之间的距离,返回频次最高的topk个中心
:return: 返回频次最高的topk个中心
'''
i= 0
sim_dict = {}
for vec1 in self.centers:
i += 1
if i <= len(self.centers):
j = i
for vec2 in self.centers[i:]:
cos = sim.vectorCosine(vec1,vec2)
# print(cos)
sim_dict[cos] = (i-1,j)
j += 1
sort_sim = sorted(sim_dict.items(),key=lambda x:x[0],reverse=True)
#print(sort_sim[:10])
num_dict = {}
for item in sort_sim[:10]:
center_nums = item[-1]
for i in center_nums:
# print(i)
if i in num_dict.keys():
num_dict[i] += 1
else:
num_dict[i] = 1
top_center = sorted(num_dict.items(),key=lambda x:x[-1],reverse=True)[:2]
#print('top_center:{}'.format(top_center))
return [num[0] for num in top_center]

6.24 把带权重的关键词渲染成词云,显示颜色,大小等,generate函数循环输出该类别的集合。代码清单如下显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def get_key_word(self,top_line_dict):
#print(top_line_dict.values())
for lines in top_line_dict.values():
line_list = []
for id in lines:
line_list.append(self.file[id])
# print(line_list)
self.get_cloud_word(line_list)
def get_cloud_word(self,word_list):
my_wordcloud = WordCloud(font_path='./data/simkai.ttf').generate(' '.join(word_list))
plt.imshow(my_wordcloud)
plt.axis("off")
plt.show()
def main(self,n_clusters):
train_data = w2v.file_embedding(self.file,self.w2v_model)
self.result,self.centers = Kmeans.train(train_data,n_clusters=n_clusters)
top_center_index = self.center_sim()
# print('结果:{}'.format(self.result))
top_line_dict = {}
for i in top_center_index:
center_id = list(self.result.keys())[i]
# print(center_id)
line_ids = self.result.get(center_id)
top_line_id = self.sim_one_centers(line_ids,self.centers[i])
top_line_dict[i] = top_line_id
self.get_key_word(top_line_dict)

6、运行效果

image-20240724105215410

image-20240724105238226

7、总结

完成本实验可掌握自然语言处理的基本方法,并使用python编程实现关于微博中社会热点话题的发现。