微博大 V 用户画像与热点话题分析

前言

该文档包含设计思路、过程和分析结果,完整代码见ipynb文档。数据集和ipynb文档地址如下:链接:https://github.com/adureychloe/weibo-data-analysize


一、查看数据

1、导入需要的包

import csv
import pandas as pd
import chardet
import jieba
import wordcloud
from PIL import Image
from jieba import analyse
import numpy as np
from pyecharts.charts import Pie
import pyecharts.options as opts
from pyecharts.charts import Map
import matplotlib.pyplot as plt
%matplotlib inline
#from pyecharts.globals import CurrentConfig, NotebookType
# CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_LAB
#CurrentConfig.ONLINE_HOST = "pyecharts-assets/assets"

2、用pandas导入数据并查看

user_df=pd.read_csv('data/data31204/userdata.csv')
user_df

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r3cSWnTe-1610720626483)(C:\Users\Reg Yang\AppData\Roaming\Typora\typora-user-images\image-20200510142412578.png)]在这里插入图片描述这里直接读取week1.csv的话会有编码问题,所以要间接用open函数里的errors参数来处理。

data_path='data/data31204/week1.csv'
df = pd.DataFrame()
encode = get_encode(data_path) # get_encode函数在上文
f = open(data_path, encoding=encode,errors='ignore')
data = pd.read_csv(f,dtype=str)
df = df.append(data)
df

在这里插入图片描述
在这里插入图片描述

用info函数来查看两个数据表的信息,info函数返回有哪些列、有多少非缺失值、每列的类型。

df:
在这里插入图片描述

user_df:
在这里插入图片描述

查看有多少是缺失值:

df:

df.isnull().sum()

在这里插入图片描述

可见retweeted_uid、geo、deleted_last_seen、permission_denied基本上全是Nan值,所以不需要考虑他们。

user_df:

user_df.isnull().sum()

在这里插入图片描述

可见user_df里没有空值。

二、清洗数据

user_df的数据不需要清洗,来看df。

随便从text中抽一条看看:

在这里插入图片描述
可见里面主要信息为中文,其余还有一些字符、@、英文,特别要注意的是,这是微博数据,也就是说[]里的内容并不是真正的文本,而是表情,如果没有注意这个,那提取关键词的时候这些表情就会变成最多的词,因为表情才是用户发的最多的,什么[哈哈]、[哭]什么的。

值得注意的是,除了这些之外,在观察了text文本数据内容,并且在后面提取了关键词后我们会发现,“转发微博”、“微博”、“哈哈”、“啊”这些词出现的频率很高,但是并没有实际含义,而且“哈哈”和“啊”这类词的长度不定,可以是任意个“哈”和“啊”,所以不能在停用词里去掉。所以根据这些,我们来清洗text文本数据。

df.text.replace(r'\[.*?\]','',regex=True,inplace=True)
df.text.replace(r'转发微博','',regex=True,inplace=True)
df.text.replace(r'轉發微博','',regex=True,inplace=True)
df.text.replace(r'微博','',regex=True,inplace=True)
df.text.replace(r'转发','',regex=True,inplace=True)
df.text.replace(r'哈*','',regex=True,inplace=True)
df.text.replace(r'啊*','',regex=True,inplace=True)
df['text']=df['text'].str.replace(r'[^\u4e00-\u9fa5]','')
df

在这里插入图片描述

得到的结果里只包含中文。但是有些行已经为空了,防止对我们后续造成影响,我们将这些空行去掉。首先填充Nan:

df.text=df.text.astype(str)
df.replace(to_replace=r'^\s*$',value=np.nan,regex=True,inplace=True)
df

在这里插入图片描述

然后去掉带Nan的行并将索引重排:

df.dropna(subset=['text'],axis=0,how='any',inplace=True)
df.reset_index(drop=True,inplace=True)
df

在这里插入图片描述

到这里为止数据就算是清理好了。

三、用户画像

先把user_df中的大V的性别和省份筛选出来。

big_v=pd.DataFrame()
big_v['province']=user_df.province[user_df.verified==True]
big_v['gender']=user_df.gender[user_df.verified==True]
big_v

在这里插入图片描述

查看性别分布:

#y_data=list(big_v['gender']).count()
gender=big_v['gender'].value_counts()
gender

在这里插入图片描述

用pyecharts画出微博大V性别分布图:

x_data=list(gender.index)
y_data=list(gender)
data_pair=list(z for z in zip(x_data,y_data))
data_pair.sort(key=lambda x:x[1])
pie=Pie()
pie.add('',data_pair=data_pair,radius='50%',center=['50%','50%'])
pie.set_global_opts(title_opts=opts.TitleOpts(title='微博大V男女比'),
    legend_opts=opts.LegendOpts(is_show=True))
pie.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
#pie.render('1.html')
pie.render_notebook()
#因为pyecharts渲染图片是从远处抓取的,所以有可能显示不出来,我就直接把图片贴在下面了
#也可以打开html看

在这里插入图片描述

可见微博大V中男性要比女性多一点,男性有124433个,女性有68539个。

接下来看省份分布,这里的省份只有代码,所以我们要先在网上找一个省份代码对照表province.txt。内容如下:

在这里插入图片描述

然后要将表big_v中的省份代码换成真正的省份名称。

province=pd.read_csv('province.txt',sep='\t',skiprows=1,names=['code','province'])
province1=province.set_index('code')
province1

在这里插入图片描述

code=list(province1.index)
def transfer(x):
    y=province1.loc[x]
    return y
big_v['place']=big_v.province[big_v['province'].isin(code)].apply(transfer)
big_v

在这里插入图片描述

查看省份分布:

place=big_v.place.value_counts()
place

在这里插入图片描述

用pyecharts画出省份地图分布:

x_place=place.index
y_place=place.values
y_place=y_place.tolist()
x_place=x_place.tolist()
data_pair1=list(z for z in zip(x_place,y_place))
pieces = [
    {'min': 60000, 'color': '#540d0d'},
    {'max': 59999, 'min': 10000, 'color': '#9c1414'},
    {'max': 9999, 'min': 5000, 'color': '#d92727'},
    {'max': 4999, 'min': 2000, 'color': '#ed3232'},
    {'max': 1999, 'min': 1000, 'color': '#f27777'},
    {'max': 999, 'min': 100, 'color': '#f7adad'},
    {'max': 0, 'color': '#f7e4e4'},
]
m=Map()
m.add("大v数量",data_pair1,'china')
#系列配置项,可配置图元样式、文字样式、标签样式、点线样式等
m.set_series_opts(label_opts=opts.LabelOpts(font_size=12),
                  is_show=False)
#全局配置项,可配置标题、动画、坐标轴、图例等
m.set_global_opts(title_opts=opts.TitleOpts(title='全国各地大v数量',pos_top=True),
                  legend_opts=opts.LegendOpts(is_show=False),
                  visualmap_opts=opts.VisualMapOpts(pieces=pieces,
                                                    is_piecewise=True,   #是否为分段型
                                                    is_show=True))       #是否显示视觉映射配置
m.render_notebook()

在这里插入图片描述

图像是交互式的,可以把鼠标移到省份上查看当前省份的大V数量:

在这里插入图片描述

在这里插入图片描述

从图中可看出大V主要集中在东部地区,这应该是因为东部地区经济更加发达,资源更多,网络条件什么的也更好,相比之下成为大V更容易的缘故。

接下来看看微博大V最常使用的客户端。

这个信息在df里,所以我们先将user_df中的大V的uid弄出来:

v_uid=list(user_df['uid'][user_df['verified']==True])

在这里插入图片描述

然后筛选出大V的客户端来源:

source_df=pd.DataFrame(df.loc[df.uid.isin(v_uid)].source)
source=source_df.source.value_counts()[:10]
source

在这里插入图片描述

还是用pyecharts画出饼图:

x_data_s=list(source.index)
y_data_s=list(source)
data_pair_s=list(z for z in zip(x_data_s,y_data_s))
data_pair_s.sort(key=lambda x:x[1])
pie=Pie()
pie.add('',data_pair=data_pair_s,radius='55%',center=['50%','50%'])
pie.set_global_opts(title_opts=opts.TitleOpts(title='微博大V客户端程序前十'),
    legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"))
pie.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
pie.render_notebook()

在这里插入图片描述

图中可以看出用新浪微博客户端的大V最多,有405282个,其次是iPhone客户端和皮皮时光机,分别有123852和99816个。

然后对大V发布微博进行关键词提取作为大V的用户标签,分为全部大V、男性大V和女性大V。

首先对df中的text进行jieba分词:

def cut_words(a):
    seg=jieba.cut(a)
    return ' '.join(seg)
df['seg_words']=df['text'].apply(cut_words) 
df.seg_words

在这里插入图片描述

把男性大V和女性大V的uid分别取出:

m_v_uid=list(user_df['uid'][user_df['verified']==True][user_df['gender']=='m'])
f_v_uid=list(user_df['uid'][user_df['verified']==True][user_df['gender']=='f'])

然后分别把所有大V、男性大V、女性大V的微博内容筛选出来:

m_text=list(df.loc[df.uid.isin(m_v_uid)].seg_words)
f_text=list(df.loc[df.uid.isin(f_v_uid)].seg_words)
v_text=list(df.loc[df.uid.isin(v_uid)].seg_words)

开始提取前100个关键词:

m = jieba.analyse.extract_tags(m_text,topK=100)
f = jieba.analyse.extract_tags(f_text,topK=100)
v = jieba.analyse.extract_tags(v_text,topK=100)

结果:

男性大V:在这里插入图片描述

女性大V:

在这里插入图片描述

所有大V:
在这里插入图片描述

词云可视化:

image_mask='pic/man1.jpg'
mask = np.array(Image.open(image_mask))
w = wordcloud.WordCloud(width = 5000, height = 1000,\
                        background_color = "white",mask =mask,\
                        font_path='font/simhei.ttf',)
w.generate(m_tag)
w.to_file("pic/man_word.png")

#画图
plt.imshow(w)
plt.axis('off')
plt.show()

男性大V:
在这里插入图片描述

女性大V:

在这里插入图片描述

所有大V:

在这里插入图片描述

四、热点话题分析

首先我们来提取排名前十的热点话题。

因为话题并不等同于关键词,而更像是一些关键词的组合,所以像上面那样直接提取关键词作为话题似乎并不科学。所以我们这里用LDA(隐含狄利克雷分布)来进行文本主题抽取。

LDA 在主题模型中占有非常重要的地位,常用来文本分类。LDA由Blei, David M.、Ng, Andrew Y.、Jordan于2003年提出,用来推测文档的主题分布。它可以将文档集中每篇文档的主题以概率分布的形式给出,从而通过分析一些文档抽取出它们的主题分布后,便可以根据主题分布进行主题聚类或文本分类。

机器学习的模型分为两种,一种是基于策略,即不能给出明确的数据分布的,一种是基于模型,可以给出分布的形式,但是超参数不知道。kmeans,dbscan是基于性能和密度的,基于策略寻找最优聚类方案,而PLSA和LDA是基于多项式分布和狄利克雷分布的,基于参数迭代寻找最优聚类方案的。

先对文本进行jieba分词:

def cut_words(a):
    seg=jieba.cut(a)
    return ' '.join(seg)
df['seg_words']=df['text'].apply(cut_words) 
df

在这里插入图片描述

单词之间都被空格区别开来,接下来对文本做向量化。

导入包:

#文本向量化
from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer

导入停用词(停用词就是一些经常在文中出现但是没有太重要意义的词),这里用的是网上找的停用词表:

在这里插入图片描述

stopword="stopwords.txt"
with open(stopword,'rb') as f:
    stopwords=f.read().decode('utf-8') #停用词提取
stoplist=stopwords.splitlines()

如果处理太多词汇的话时间太长,于是这里我就只从文本中提取1000个最重要的特征关键词,并进行向量转换。

n_features=1000
tf_vectorizer=TfidfVectorizer(
                                max_features=n_features,
                                stop_words=stoplist,
                                max_df=0.5,
                                min_df=10
                             )
tf=tf_vectorizer.fit_transform(df.seg_words)
tf.shape

在这里插入图片描述

提取的向量矩阵大小为(3777777,1000)。

导入LDA包:

from sklearn.decomposition import LatentDirichletAllocation

LDA需要人为设定主题数量,这里我选择30个,然后再取前10个主题。

n_topics=30
lda=LatentDirichletAllocation(n_topics=n_topics,
                                #learning_method='batch',
                                learning_method='online',
                                max_iter=20,
                                learning_offset=50.,
                                random_state=0,
                                batch_size=128,
                                verbose=1)
lda.fit(tf)

主题并没有确定的名称,而是用一系列关键词相结合形成的。模型fit后,需要定义每个主题输出多少个关键词,这里暂定输出前20个关键词:

def print_topic(model,feature_names,n_top_words):
    for idx,topic in enumerate(model.components_):
        if(idx<10):
            print("Topic{}".format(idx))
            print(" ".join([feature_names[i] for i in 		    		 	topic.argsort()[:-n_top_words-1:-1]]))
        else:
            break
    print()

n_top_words=20
tf_feature_names=tf_vectorizer.get_feature_names()
print_topic(lda,tf_feature_names,n_top_words)

输出结果:

在这里插入图片描述

在这里插入图片描述

可以大概看出每个主题大概是什么。比如第一个大概是关于电影明星的,第四个大概是抽奖、祝福之类的,第十个大概是关于人生鸡汤之类的。

这里可以用pyLDAvis来可视化:

import pyLDAvis
import pyLDAvis.sklearn
pyLDAvis.enable_notebook()
pyLDAvis.sklearn.prepare(lda,tf,tf_vectorizer)

在这里插入图片描述

在这里插入图片描述

在图的左侧,是用圆圈代表不同的主题,圆圈的大小代表每个主题分别包含文章的数量。可以看到30个主题大概聚成了三堆,聚成一堆的代表他们主题比较相似。

当鼠标没有指向任何主题的时候,右侧的30个关键词代表全部文本中提取到的30个最重要关键词。大概是“喜欢、关注、男人、女人、加油”这些词。

如果把鼠标放到某个主题(这里是主题一)下:
在这里插入图片描述

右侧的关键词列表就会变化,红色展示了每个关键词在当前主题下的频率。

接下来我们来分析不同时间段的热点话题,看下热点话题的演化过程。

时间数据在df的created_at字段里,先来看一下数据:

在这里插入图片描述

这些数据是object,不好操作,所以需要把它转化成时间序列。

#将created_at转成时间序列
time_data=pd.to_datetime(df['created_at'],format='%Y-%m-%d')
df['time']=time_data

然后把它作为索引并排序:

#将时间序列作为索引并升序排序
date_index=df.set_index(['time'])
date_index=date_index.sort_index(ascending=True)
date_index

在这里插入图片描述

看一下时间序列:

date_index.index

在这里插入图片描述

可以看到时间为从2012-01-02到2012-01-08。我就分成2号-4号、5号-7号、8号-9号来研究不同时间的热点话题。

date_1=list(date_index['2012-01-02':'2012-01-04']['seg_words'])
date_2=list(date_index['2012-01-05':'2012-01-06']['seg_words'])
date_3=list(date_index['2012-01-07':'2012-01-08']['seg_words'])
print(len(date_1),len(date_2),len(date_3))

在这里插入图片描述

类似上面的,分别从文本中提取1000个最重要的特征关键词,并进行向量转换。

n_features=1000
tf_vectorizer_1=CountVectorizer(strip_accents='unicode',
                                max_features=n_features,
                                stop_words=stoplist,
                                max_df=0.5,
                                min_df=10)
tf_vectorizer_2=CountVectorizer(strip_accents='unicode',
                                max_features=n_features,
                                stop_words=stoplist,
                                max_df=0.5,
                                min_df=10)
tf_vectorizer_3=CountVectorizer(strip_accents='unicode',
                                max_features=n_features,
                                stop_words=stoplist,
                                max_df=0.5,
                                min_df=10)
tf_1=tf_vectorizer_1.fit_transform(date_1)
tf_2=tf_vectorizer_2.fit_transform(date_2)
tf_3=tf_vectorizer_3.fit_transform(date_3)

进行LDA主题抽取,这里只选取5个主题:

n_topics=5
lda_1=LatentDirichletAllocation(n_topics=n_topics,
                                #learning_method='batch',
                                learning_method='online',
                                max_iter=20,
                                learning_offset=50.,
                                random_state=0,
                                batch_size=128,
                                verbose=1)
lda_2=LatentDirichletAllocation(n_topics=n_topics,
                                #learning_method='batch',
                                learning_method='online',
                                max_iter=20,
                                learning_offset=50.,
                                random_state=0,
                                batch_size=128,
                                verbose=1)  
lda_3=LatentDirichletAllocation(n_topics=n_topics,
                                #learning_method='batch',
                                learning_method='online',
                                max_iter=20,
                                learning_offset=50.,
                                random_state=0,
                                batch_size=128,
                                verbose=1)                          

第一阶段的热点话题:
在这里插入图片描述

第二阶段的热点话题:

在这里插入图片描述

第三阶段的热点话题:

在这里插入图片描述

最后来总结一下热点话题形成的特点和关键因素。

首先当然是微博大V发布和转发的消息会更容易成为热点话题,而从大V的用户画像中可以看出来自北京、上海、广东等发达地区的大V数量更多,他们引起的热点话题也就多。

其次是一条微博的转发量。转发量越多,自然话题变成热点话题的概率也就更大。

还有就是各种重大节日和事件的发生。比如像是情人节,恋爱、感情就会变成热点话题,而如果是奥运会开幕这种事件,运动员就会变成热点话题。热点话题是随着时间和事件的发生决定的。

而关于工作、生活、学习之类的事情,其实一直都是热点话题,一直被人们所讨论。

同时,男性和女性各自的热点话题也会有所差异。

以上就是我的微博大V数据分析报告。详细代码见ipynb文档。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值