系列文章:html
爬虫实战(一):爬取微博用户信息python
爬虫实战(三):微博用户信息分析github
该系列文章介绍了什么?算法
1.爬虫分析和处理方法数据库
2.Python中的数据库操做方法数组
3.Selenium浏览器自动化以及无头浏览器使用方法浏览器
4.对数据进行词云分析的方法bash
5.对数据进行可视化的方法app
6.LDA隐含狄利克雷分布模型的建模和使用方法
前面 这篇文章 介绍了爬取微博用户资料和动态并将数据保存在数据库的过程。下面来讲一下对数据库数据与分析的过程。
首先先来回顾一下前一篇文章中谈到的数据库字段。下图是 weibo 数据库中的三张表:
其中每一个字段对应的含义请见源码。
再来看一下数据库中每张表里面的内容,首先是用户资料表中的内容:
能够看到和微博资料页的资料是对应的。
再来看看用户动态数据表:
里面包含了用户动态内容和动态发布时间,因此咱们首先想到能够对微博动态内容进行处理。
了解了数据库结构之后,咱们能够对微博动态和动态发布时间进行可视化处理,在这里,笔者作了如下几点分析:
- 微博动态发布时间处理:画出微博发布时间统计图
- 微博动态简单可视化:词云
- 微博动态词频处理:词频统计以及生成词频图
以上三种分析程序均位于 Data_analysis.py 中, 其 main 函数代码以下:
#能够指定须要分析的用户的uid(必须先存在conf.yaml里面,而且运行了一次爬虫程序)
def main(uid):
time_lists,str=get_time_str(uid)#将数据库中的微博动态转化为字符串
plot_create_time(time_lists)#画出微博发布时间统计图
with open('data/stop_words.txt') as f:
stop_words = f.read().split('\n')
str=format_content(str)#去掉表情和一些没必要要的符号
word_list=word_segmentation(str,stop_words)#分词并去除停用词
create_wordcloud(word_list) #画出词云
counter = word_frequency(word_list, 10)# 返回前 top_N 个值,若是不指定则返回全部值
print(counter)
plot_chart(counter)#会生成词频图保存在weibo_wordfrq.html中
复制代码
那么这三种分析具体如何实现呢?接下来笔者将对其进行一一阐述。
要对微博动态内容进行可视化分析,第一步是要将微博动态内容整合到一块儿,下面这段代码是将用户微博中的全部动态拼接到一块儿,也就是 main 函数里面的第一行代码所调用的函数。
# time_lists,str=get_time_str(uid)# main 函数第一行代码
# 将数据库中的微博动态转化为字符串
def get_time_str(uid):
_, engine = Connect('../conf.yaml') # 链接数据库
conn = engine.connect()
metadata = MetaData(engine)
wb_data = Table('wb_data',metadata, autoload=True)
s = select([wb_data]).where(wb_data.c.uid == uid) #从wb_data表中选择uid对应的数据
res = conn.execute(s)
conn.close()
str = ''
time_lists = []
for row in res:
str += row[2] + '\n'#拼接动态字段
time_lists.append(row[3]) #将时间转化为列表对象,方便后续处理
return time_lists, str
复制代码
返回的 time_lists
为动态发布时间列表, str
为全部动态拼接到一块儿的最终字符串.在这里由于是对时间进行统计,因此咱们只须要关注 time_lists
这个列表.先来看看这个列表里面存放的具体内容:
[....,'02月02日 29', '01月21日 30', '01月20日 31', '01月10日 32', '01月02日 33', '01月01日 34', '2017-11-30', '2017-11-29', '2017-11-04', '2017-10-29', '2017-10-27',...]
复制代码
这是我特地取的一段,恰好两种格式的时间都包含在内。这个列表里面包含的时间是从最近的月份和日期到最初的年份-月份-日期.例如上面的 '2017-11-30'
前面的日期格式均是 XX月XX日XX ,而 '01月01日 34'
后面的同理均是 20XX-XX-XX ,排序方式是由近到远 。在这里,我考虑分析天天发布的微博动态数和时间的变化趋势,而且将时间排列为离如今越远离原点越近。
因而便有了下面这段代码:
# plot_create_time(time_lists)# main 函数第二行代码
#画出微博发布时间的统计图
def plot_create_time(time_lists):
recent_time = re.compile(r'\d{2}月\d{2}日',re.S)
long_time = re.compile(r'(\d{4}-\d{2}-\d{2})',re.S)
tmp_lists = []#保存**月**日格式的数据
tmp_nums = []#统计**月**日发帖数量
long_lists = []#保存20**-**-**格式的数据
long_nums = []#统计20**-**-**发帖数量
for t in time_lists:
res = re.findall(recent_time, t)
if(res):#res[0]为**月**日格式的数据
if(not tmp_lists or res[0]!= tmp_lists[-1]):#列表为空或者不与前一个日期重复
tmp_lists.append(res[0])
tmp_nums.append(1)
else:#与前一个日期重复,计数加一
tmp_nums[-1]+=1
else:#res[0]20**-**-**格式的数据
res = re.findall(long_time,t)
if(not long_lists or res[0]!=long_lists[-1]):
long_lists.append(res[0])
long_nums.append(1)
else:
long_nums[-1]+=1
#将时间按照从远到进的顺序排列
tmp_lists.reverse()
tmp_nums.reverse()
long_lists.reverse()
long_nums.reverse()
time_list = long_lists + tmp_lists
time_nums = long_nums + tmp_nums
#调用 pyecharts 包渲染出统计图
chart = Bar('用户微博动态发布时间')
chart.add('动态数', time_list, time_nums, is_more_utils=True,datazoom_range=[10,40],is_datazoom_show=True)
chart.render("weibo_dynamic.html")
复制代码
因而微博发布时间统计图便画出来了,是一个动态的图,效果以下:
要对动态内容进行分析,首先要进行分词处理,而且,咱们知道经常使用词语中有不少语气词等,会影响关键词语的权重,因此在进行分析以前须要去掉这些词语,这种词语在信息检索叫作 停用词 。此外,动态中含有的换行符,html代码等没必要要的符号也须要去掉。
因此 main 函数中在获得词云以前有下面四行代码:
with open('data/stop_words.txt') as f:#从保存有停用词的文件中读取停用词
stop_words = f.read().split('\n')
str=format_content(str)# 去掉表情和一些没必要要的符号
word_list=word_segmentation(str,stop_words)#分词并去除停用词
复制代码
其中调用了 word_segmentation
函数,该函数的内容以下:
# 分词并去除停用词
def word_segmentation(content, stop_words):
# 使用 jieba 分词对文本进行分词处理
jieba.enable_parallel()
seg_list = jieba.cut(content)
seg_list = list(seg_list)
# 去除停用词
user_dict = [' ', '哒']
filter_space = lambda w: w not in stop_words and w not in user_dict
word_list = list(filter(filter_space, seg_list))
return word_list
复制代码
在这里,我使用 jieba 进行分词,再对分词结果进行过滤,去除停用词,并返回该分词结果列表。而后使用 word_list
中的数据来画出词云,具体代码以下:
#create_wordcloud(word_list) # main 函数第7行代码
#画出词云
def create_wordcloud(content,image='weibo.jpg',max_words=5000,max_font_size=50):
cut_text = " ".join(content)
cloud = WordCloud(
# 设置字体,不指定就会出现乱码
font_path="HYQiHei-25J.ttf",
# 容许最大词汇
max_words=max_words,
# 设置背景色
# background_color='white',
# 最大号字体
max_font_size=max_font_size
)
word_cloud = cloud.generate(cut_text)
word_cloud.to_file(image)
复制代码
最后获得结果 weibo.jpg ,打开看一看:
这就是词云分析的结果,读者能够根据本身须要,好比若是以为原文和转发出现频率高价值不高能够加入停用词中进行过滤。
对微博动态中的词语出现的频率进行统计处理,首先须要词语列表,由于在词云分析中咱们已经获得了过滤掉停用词的词语列表 word_list
,因此在这里能够直接拿来使用:
#counter = word_frequency(word_list, 10)# main 函数倒数第三行代码
# 词频统计
# 返回前 top_N 个值,若是不指定则返回全部值
# from collections import Counter
def word_frequency(word_list, *top_N):
if top_N:
counter = Counter(word_list).most_common(top_N[0])
else:
counter = Counter(word_list).most_common()
return counter
复制代码
获得的 counter
内容为词语以及出现的次数组成的列表,例如:
[('感受', 11), ('代码', 10), ('说', 9),('晚上', 9), ('终于', 7), ('麻蛋', 6), ('写', 6), ('数据', 5), ('学校', 5), ('朋友', 4)]
复制代码
而后根据获得的词频画图并渲染:
# plot_chart(counter)# main 函数最后一行,会生成词频图保存在weibo_wordfrq.html中
#画出词频图,默认为柱状图
def plot_chart(counter, chart_type='Bar'):
items = [item[0] for item in counter]
values = [item[1] for item in counter]
if chart_type == 'Bar':
chart = Bar('微博动态词频统计')
chart.add('词频', items, values, is_more_utils=True)
else:
chart = Pie('微博动态词频统计')
chart.add('词频', items, values, is_label_show=True, is_more_utils=True)
chart.render('weibo_wordfrq.html')
复制代码
最后获得排名前10位的词语频率统计图:
咱们忙活了好久,对用户动态进行了多种分析,可是用户的偏好和个性感受仍是没有把握得很清楚,那么这时候就须要使用一种方法从海量信息中抽取关键部分,最好是能提取出主题,受以前这篇论文[1] 的启发,笔者得知 LDA 即是一种可以知足上述条件的很好的分析方法。
隐含狄利克雷分布(英语:Latent Dirichlet allocation,简称LDA)是一种主题模型,它能够将文档集中每篇文档的主题按照几率分布的形式给出。同时它是一种无监督学习算法,在训练时不须要手工标注的训练集,须要的仅仅是文档集以及指定主题的数量k便可。此外LDA的另外一个优势则是,对于每个主题都可找出一些词语来描述它。
以上说明摘录自维基百科.
本文着眼点在于实践,因此只介绍在 python 中使用 LDA 进行分析的方法,并不阐述 LDA 的原理。更况且,在计算机科学和数据科学的学术讲座中,讲者在介绍到LDA时,都每每会把原理这部分直接跳过去。
该部分代码位于 LDA_Analysis.py ,首先能够看看 main 函数的内容:
def main(uid):
wordlists, uid = getwords(uid)#获取分词列表
lda, tf, tf_feature_names, tf_vectorizer = word2vec(wordlists)#将单词转化为向量
Save_Topic_Words(lda, tf_feature_names, uid)#保存主题到数据库
pyLDAvisUI(lda, tf, tf_vectorizer)#根据主题结果进行渲染
复制代码
第一步即是像以前那样进行分词并过滤停用词,调用了 getwords
函数,代码以下:
#获取微博动态数据
def getwords(uid):
_,str = get_time_str(uid) # 将数据库中的微博动态转化为字符串,能够指定uid(conf.yaml里面的)
with open('data/stop_words.txt') as f:
stop_words = f.read().split('\n')
str = format_content(str)
word_list = word_segmentation(str, stop_words) # 分词并去除停用词
return word_list,uid
复制代码
该函数内容和以前介绍的 Data_analysis.py 中的效果同样,故在此不累述。
而后使用 sklearn 机器学习包中自带的 LDA 处理方法进行处理,代码以下:
#lda, tf, tf_feature_names, tf_vectorizer = word2vec(wordlists)# main 函数第二行代码
#使用LDA进行微博动态主题建模与分析
def word2vec(word_list,n_features=1000,topics = 5):
tf_vectorizer = CountVectorizer(strip_accents='unicode',
max_features=n_features,
#stop_words='english',已经进行过停用词处理故不用重复处理
max_df=0.5,
min_df=10)
tf = tf_vectorizer.fit_transform(word_list)
lda = LatentDirichletAllocation(n_components=topics,#主题数
learning_method='batch',
#样本量不大只是用来学习的话用"batch"比较好,这样能够少不少参数要调
)
#用变分贝叶斯方法训练模型
lda.fit(tf)
#依次输出每一个主题的关键词表
tf_feature_names = tf_vectorizer.get_feature_names()
return lda,tf,tf_feature_names,tf_vectorizer #返回模型以及主题的关键词表
复制代码
最后咱们将主题以可视化结果展示出来:
#pyLDAvisUI(lda, tf, tf_vectorizer) # main 函数中最后一行
#将主题以可视化结果展示出来
def pyLDAvisUI(lda,tf,tf_vectorizer):
page = pyLDAvis.sklearn.prepare(lda, tf, tf_vectorizer)
pyLDAvis.save_html(page, 'lda.html') #将主题可视化数据保存为html文件
复制代码
获得 lda.html ,为渲染之后的结果:
至此,用户信息分析介绍结束。
参考:[1]陆飞.面向社会工程学的SNS分析和挖掘[D].上海:上海交通大学,2013.