这个项目属于哪个课程 | 2023数据采集与融合技术 |
---|---|
作业要求 | 综合设计——多源异构数据采集与融合应用综合实践 |
组名 | 汪汪队 |
项目主题 | 微博评论情感分析 |
项目简介 | 项目需求:1. 情绪监测、2. 品牌声誉管理、3. 市场分析、4. 舆论引导、5. 个性化推荐、6. 社交网络分析 项目目标: 1. 情绪识别、2. 情感分类、3. 观点提取、4. 情绪监测、5. 市场趋势预测、6. 个性化推荐、7. 社交网络分析 项目开展技术路线:1. 数据收集、2. 数据预处理、3. 模型选择与训练、4. 情感分析、5. 结果分析与可视化、6. 搭建网页 |
团队成员学号 | 组长:102102130张明康 组员: 102102131张铭玮 102102128汪伟杰 102102129张昊 102102133陈灿铭 |
这个项目的目标 | 1. 情绪识别:准确识别评论表达的情绪倾向,如正面情绪、负面情绪或中性情绪。这是情感分析的基础任务,也是其他应用场景的前提。 2. 情感分类:对评论进行细致的情感分类,如愤怒、喜悦、悲伤等,以便更深入地了解用户的情感状态。 3. 观点提取:从评论中提取出用户对某一事件、话题或产品的观点和看法,为舆情分析、市场调查等领域提供有价值的信息。 4. 情绪监测:通过对微博评论的情感分析,实时监测公众情绪的变化趋势,为情绪监测和舆情管理提供数据支持。 5. 市场趋势预测:通过分析用户对产品或服务的情感态度,预测市场趋势和消费者需求,为企业市场策略制定提供参考。 6. 个性化推荐:根据用户的情感倾向,为用户推荐更符合其兴趣和需求的内容,提高用户体验。 7. 社交网络分析:通过分析微博评论的情感倾向,研究社交网络中用户之间的关系和影响力,为社交网络分析提供数据支持。 |
参考文献 | 【深度学习】详解TextCNN [NLP] 文本分类之TextCNN模型原理和实现(超详细) Python数据可视化:折线图、柱状图、饼图代码 【干货】Python:wordcloud库绘制词云图 python绘制雷达图(详细) |
项目介绍
微博评论情感分析项目是基于自然语言处理(NLP)技术,对微博平台上的用户评论进行情感倾向性判定的研究与应用。
项目的主要目标是通过对微博评论的情感分析,了解广大用户的情绪状态、观点倾向,从而为情绪监测、品牌声誉管理、市场分析等领域提供有价值的数据支持。
具体而言,本项目包括以下几个阶段:
- 数据收集:通过爬虫技术或API接口从微博平台获取评论数据。考虑到数据的多样性和真实性,往往会选取带有用户图片和文本双重信息的评论数据。
- 数据预处理:清洗数据,去除噪声,如HTML标签、特殊字符等;然后进行分词处理,把文本分解为更易分析的单元,如词、短语等。
- 特征工程:从预处理后的文本中提取特征,如词频、词向量、语法结构等,为机器学习模型准备输入。
- 模型训练:使用机器学习算法TestCNN训练模型。深度学习框架常被用于构建复杂的网络模型。
- 情感分析:将训练好的模型应用于新的数据集上,输出情感分析结果,如正面情绪、负面情绪或中性情绪。
- 结果分析与应用:根据模型输出的情感分析结果,进行数据可视化、趋势分析等,为情绪监测、品牌管理、市场分析等领域提供依据。
- 搭建网页:使用streamlit搭建网页,展示爬取的数据以及可视化结果。
微博评论情感分析项目在实施过程中可能会遇到数据量大、语言多样、情感表达复杂等挑战。因此,项目往往需要结合最新的NLP技术,如深度学习、迁移学习等,以及领域专业知识,才能达到较好的分析效果。
项目需求
微博评论情感分析的需求主要来源于以下几个方面:
- 情绪监测:通过分析微博评论的情感倾向,可以了解公众对于某一事件、话题或产品的情绪态度,为情绪监测提供数据支持。
- 品牌声誉管理:企业可以通过微博评论情感分析了解消费者对其产品或服务的满意度和不满意度,以及消费者对品牌形象的评价,从而更好地进行品牌声誉管理。
- 市场分析:通过对微博评论的情感分析,可以了解消费者对某一产品或服务的需求、喜好和期望,为企业市场策略的制定提供参考。
- 舆论引导:政府和媒体可以通过微博评论情感分析了解公众对某一事件或政策的看法和态度,从而进行舆论引导和舆情管理。
- 个性化推荐:微博平台可以根据用户的评论情感倾向,为用户推荐更符合其兴趣和需求的内容,提高用户体验。
- 社交网络分析:通过分析微博评论的情感倾向,可以了解社交网络中用户之间的关系和影响力,为社交网络分析提供数据支持。
为了满足上述需求,微博评论情感分析项目需要具备以下特点:
- 准确性:能够准确识别微博评论的情感倾向,避免误判和漏判。
- 实时性:能够快速处理大量评论数据,实时反馈情感分析结果。
- 鲁棒性:能够应对不同语言风格、语境和噪声环境的干扰,保持稳定的数据分析效果。
- 可扩展性:能够适应不同领域的需求,灵活扩展情感分析的应用范围。
- 隐私保护:在数据收集和分析过程中,确保用户隐私得到保护,遵守相关法律法规。
项目目标
微博评论情感分析的目标主要包括以下几点:
- 情绪识别:准确识别评论表达的情绪倾向,如正面情绪、负面情绪或中性情绪。这是情感分析的基础任务,也是其他应用场景的前提。
- 情感分类:对评论进行细致的情感分类,如愤怒、喜悦、悲伤等,以便更深入地了解用户的情感状态。
- 观点提取:从评论中提取出用户对某一事件、话题或产品的观点和看法,为舆情分析、市场调查等领域提供有价值的信息。
- 情绪监测:通过对微博评论的情感分析,实时监测公众情绪的变化趋势,为情绪监测和舆情管理提供数据支持。
- 市场趋势预测:通过分析用户对产品或服务的情感态度,预测市场趋势和消费者需求,为企业市场策略制定提供参考。
- 个性化推荐:根据用户的情感倾向,为用户推荐更符合其兴趣和需求的内容,提高用户体验。
- 社交网络分析:通过分析微博评论的情感倾向,研究社交网络中用户之间的关系和影响力,为社交网络分析提供数据支持。
总之,微博评论情感分析的目标是通过对评论数据的情感分析,为情绪监测、市场分析、个性化推荐等各个领域提供有价值的信息和数据支持。
项目开展技术路线
微博评论情感分析的项目开展技术路线可以分为以下几个阶段:
- 数据收集:
- 使用爬虫技术或微博API获取微博评论数据。
- 数据预处理:
- 对原始数据进行预处理
- 模型选择与训练:
- 使用TestCNN模型进行训练
- 情感分析:
- 将训练好的模型应用于新的数据集上,输出情感分析结果
- 结果分析与可视化:
- 对情感分析结果进行数据可视化、趋势分析等,以便更直观地展示和分析数据。
- 搭建网页:
- 使用streamlit搭建网页,展示爬取的数据以及可视化结果
在整个技术路线中,可能需要应对数据量大、语言多样、情感表达复杂等挑战。因此,项目开展过程中需要结合最新的自然语言处理(NLP)技术和领域专业知识,以达到较好的情感分析效果。
我完成的任务——可视化
情感分布饼状图和雷达图
emograpic(dic)
def emograpic(dic):
a=[]
b=[]
for key in dic:
a.append(key)
b.append(dic[key])
size=[]
t=sum(b)#统计总的发表篇幅
label=a
for u in b:
i=u/t
size.append(i)
colors = ["#5D7599","#ABB6C8","#DADADA","#F7F0C6","#C2C4B6","#B6B4C2","#AAC9CE"]
testttt = [list(z) for z in zip(a,b)]
from pyecharts.charts import Radar
j = 0
for i in b:
if i > j:
j = i
print(b,j)
z = a
print(z)
radar = Radar(init_opts=opts.InitOpts(
width='700px',
height='500px',
page_title='page',
))
radar.add_schema(
schema=[
opts.RadarIndicatorItem(name=z[0], max_=j),
opts.RadarIndicatorItem(name=z[1], max_=j),
opts.RadarIndicatorItem(name=z[2], max_=j),
opts.RadarIndicatorItem(name=z[3], max_=j),
opts.RadarIndicatorItem(name=z[4], max_=j),
opts.RadarIndicatorItem(name=z[5], max_=j),
opts.RadarIndicatorItem(name=z[6], max_=j),
],
splitarea_opt=opts.SplitAreaOpts(
is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
),
textstyle_opts=opts.TextStyleOpts(color="#000"),
).set_series_opts(label_opts=opts.LabelOpts(is_show=True,color=["#4e79a7"])).add("人数雷达图", [b],color=["#4e79a7"]).set_global_opts(
legend_opts=opts.LegendOpts()
).render("radar.html")
css = (
Pie( init_opts=opts.InitOpts(
width='900px',
height='500px',
page_title='page',
))
.add(
"",
testttt,
radius=["40%", "55%"],
label_opts=opts.LabelOpts(
position="outside",
formatter="\n{hr|}\n {b|{b}: }{c} {per|{d}%} ",
background_color="#eee",
border_color="#aaa",
border_width=1,
border_radius=4,
rich={
"a": {"color": "#999", "lineHeight": 22, "align": "center"},
"abg": {
"backgroundColor": "#e3e3e3",
"width": "100%",
"align": "right",
"height": 22,
"borderRadius": [4, 4, 0, 0],
},
"hr": {
"borderColor": "#aaa",
"width": "100%",
"borderWidth": 0.5,
"height": 0,
},
"b": {"fontSize": 16, "lineHeight": 33},
"per": {
"color": "#eee",
"backgroundColor": "#334455",
"padding": [2, 4],
"borderRadius": 2,
},
},
),
)
.render("pie_rich_label.html")
)
-
该函数使用 Pyecharts 库生成情感分布的饼状图和雷达图。
-
首先,它将字典 dic 中的情感类别和对应计数信息提取为两个列表 a 和 b。
-
然后,计算每个情感所占的比例,并通过 Pyecharts 的 Radar 组件生成雷达图。最后,将生成的图表保存为 HTML 文件。
-
emograpic(counts):
- 这是 emograpic 函数的一个特例,接受一个包含不同情感类别计数信息的字典 counts。这个函数生成情感分布的饼状图和雷达图。
点赞-情感关系柱状图
like_emo(str, lk_em_dict):
def like_emo(str,lk_em_dict):
# lk_em_dict = {}s
j = str.split(',')[4]
emo = j.split('\n')[0]
lkcnt = str.split(',')[3]
if (emo in lk_em_dict) == True:
lk_em_dict[emo] += int(lkcnt)
else:
lk_em_dict[emo] = int(lkcnt)
-
该函数从输入字符串中提取点赞数和情感信息,并更新字典 lk_em_dict,其中存储了不同情感类别的点赞总数。
-
这个函数是为了后续生成点赞-情感关系的柱状图。
lk_em_graphic(dic)
def lk_em_graphic(dic):
a=[]
b=[]
for key in dic:
a.append(key)
b.append(dic[key])
size=[]
t=sum(b)#统计总的发表篇幅
label=a
plt.rcParams['font.sans-serif']=['Microsoft JhengHei']
#计算每种类型所占的比例
for u in b:
size.append(u)
# plt.plot(size)
colors = ["#5D7599","#ABB6C8","#DADADA","#F7F0C6","#C2C4B6","#B6B4C2","#AAC9CE"]
plt.figure(figsize = (10,10))
plt.title("情绪-点赞关系柱状图", fontsize=15,fontweight='bold')
plt.xlabel("情绪", fontsize=15,fontweight='bold')
plt.ylabel("总点赞数", fontsize=15,fontweight='bold')
# 修改坐标轴字体及大小
plt.yticks(fontproperties='Times New Roman', size=15,weight='bold')#设置大小及加粗
plt.xticks(fontproperties='Times New Roman', size=15)
# 设置标题
plt.rcParams['font.sans-serif'] = ['KaiTi'] # 用来正常显示中文标签,如果想要用新罗马字体,改成 Times New Roman
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.tight_layout() # 解决绘图时上下标题重叠现象
#画线
plt.bar(a, b, color=colors, width=0.5)
# plt.plot(a,b)
plt.savefig("pics/lk_emo.jpg",bbox_inches='tight',pad_inches=0.0)
# plt.show()
c = (
Bar(init_opts=opts.InitOpts(
width='700px',
height='400px',
page_title='page',
)).add_xaxis(a)
.add_yaxis("点赞数",b)
.render("emolk.html")
)
-
接受一个字典 dic,其中包含不同情感类别的点赞数信息。
-
使用 Matplotlib 生成情感-点赞关系的柱状图,并将图表保存为 HTML 文件。
省份-情感关系折线图和地理分布图
province(str, dict):
def province(str,dict):
j = str.split(',')[4]
emo = j.split('\n')[0]
province = str.split(',')[1]
isinDict(dict[emo],province)
-
从输入字符串中提取省份和情感信息,并更新字典 dict,其中存储了不同省份和情感类别的计数信息。
-
这个函数是为了后续生成省份-情感关系的折线图和地理分布图。
pe_graphic(dic)
def pe_graphic(dic):
pe_emo = {}
allprovince = {}
cnt = 0
for i in dic:
for j in dic[i]:
print(j)
if (j in allprovince) == True:
allprovince[j]+=dic[i][j]
# cnt+=dic[i][j]
else:
allprovince[j] = dic[i][j]
# cnt+=dic[i][j]
for i in allprovince:
pe_emo[i] = {}
for j in dic:
pe_emo[i][j] = 0
for i in dic:
for j in dic[i]:
pe_emo[j][i]+=dic[i][j]
x_gra = []
y_gra = {}
y_gra2 = {}
a = []
b = []
print(allprovince)
for ia in allprovince:
a.append(ia)
b.append(allprovince[ia])
c = (
Bar(init_opts=opts.InitOpts(
width='700px',
height='400px',
page_title='page',
)).add_xaxis(a)
.add_yaxis("各省人数",b)
.render("procnts.html")
)
for i in pe_emo:
# print[i]
x_gra.append(i)
for j in pe_emo[i]:
print(j)
# y_gra[j].append(i[j])
if (j in y_gra) == True:
y_gra[j].append(pe_emo[i][j]/allprovince[i])
y_gra2[j].append(pe_emo[i][j])
else:
y_gra[j] = [pe_emo[i][j]/allprovince[i]]
y_gra2[j] = [pe_emo[i][j]]
# print(allprovince)
# print(allprovince,cnt,pe_emo)
plt.rcParams['font.sans-serif']=['Microsoft JhengHei']
plt.figure(figsize = (13,7))
plt.ylim((0, 100))
plt.rcParams['font.sans-serif'] = ['KaiTi'] # 用来正常显示中文标签,如果想要用新罗马字体,改成 Times New Roman
plt.rcParams['axes.unicode_minus'] = False
plt.title("情绪-省份关系折线图", fontsize=15,fontweight='bold')
plt.xlabel("省份", fontsize=15,fontweight='bold')
plt.ylabel("情感倾向占比", fontsize=15,fontweight='bold')
# 修改坐标轴字体及大小
from pyecharts.charts import Line
line=(
Line(init_opts=opts.InitOpts(
width='1400px',
height='500px',
page_title='page',
))
.set_global_opts(
# tooltip_opts=opts.TooltipOpts(is_show=False),
xaxis_opts=opts.AxisOpts(type_="category"),
yaxis_opts=opts.AxisOpts(
type_="value",
axistick_opts=opts.AxisTickOpts(is_show=True),
splitline_opts=opts.SplitLineOpts(is_show=True),
),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
datazoom_opts=opts.DataZoomOpts(is_show=True, type_ = "slider",)
)
.add_xaxis(xaxis_data=x_gra)
.add_yaxis(
series_name="like",
y_axis=y_gra["like"], is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name="disgust",
y_axis=y_gra["disgust"], is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name="surprise",
y_axis=y_gra["surprise"], is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name="anger",
y_axis=y_gra["anger"], is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name="fear",
y_axis=y_gra["fear"], is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name="sadness",
y_axis=y_gra["sadness"], is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name="happiness",
y_axis=y_gra["happiness"], is_smooth=True,
label_opts=opts.LabelOpts(is_show=False),
)
.render("nwpe.html")
)
from pyecharts.charts import Map,Timeline
c1 = (
Map()
.add("like", [list(z) for z in zip(x_gra, y_gra2["like"])], "china")
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(y_gra2["like"]),
min_=min(y_gra2["like"]),
range_color=["#EFEFEF","#BEFB66","#EB672F","#EA3725"]
),
)
)
c2 = (
Map()
.add("disgust", [list(z) for z in zip(x_gra, y_gra2["disgust"])], "china")
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(y_gra2["disgust"]),
min_=min(y_gra2["disgust"]),
range_color=["#DEDEF7","#BEFB66","#EB672F","#EA3725"]
),
)
)
c3 = (
Map()
.add("surprise", [list(z) for z in zip(x_gra, y_gra2["surprise"])], "china")
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(y_gra2["surprise"]),
min_=min(y_gra2["surprise"]),
range_color=["#DEDEF7","#BEFB66","#EB672F","#EA3725"]
),
)
)
c4 = (
Map()
.add("anger", [list(z) for z in zip(x_gra, y_gra2["anger"])], "china")
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(y_gra2["anger"]),
min_=min(y_gra2["anger"]),
range_color=["#DEDEF7","#BEFB66","#EB672F","#EA3725"]
),
)
)
c5 = (
Map()
.add("fear", [list(z) for z in zip(x_gra, y_gra2["fear"])], "china")
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(y_gra2["fear"]),
min_=min(y_gra2["fear"]),
range_color=["#DEDEF7","#BEFB66","#EB672F","#EA3725"]
),
)
)
c6 = (
Map()
.add("sadness", [list(z) for z in zip(x_gra, y_gra2["sadness"])], "china")
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(y_gra2["sadness"]),
min_=min(y_gra2["sadness"]),
range_color=["#DEDEF7","#BEFB66","#EB672F","#EA3725"]
),
)
)
c7 = (
Map()
.add("happiness", [list(z) for z in zip(x_gra, y_gra2["happiness"])], "china")
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(y_gra2["happiness"]),
min_=min(y_gra2["happiness"]),
range_color=["#DEDEF7","#BEFB66","#EB672F","#EA3725"]
),
)
)
timeline = Timeline()
timeline.add(c1,"like")
timeline.add(c2,"disgust")
timeline.add(c3,"surprise")
timeline.add(c4,"anger")
timeline.add(c5,"fear")
timeline.add(c6,"sadness")
timeline.add(c7,"happiness")
timeline.render("new_map.html")
plt.plot(x_gra, y_gra["like"], marker='o', markersize=7,label = "like")
plt.plot(x_gra, y_gra["disgust"], marker='o', markersize=7,label = "disgust",linewidth = "7",color = 'red')
plt.plot(x_gra, y_gra["surprise"], marker='o', markersize=7,label ="surprise" )
plt.plot(x_gra, y_gra["anger"], marker='o', markersize=7,label = "anger")
plt.plot(x_gra, y_gra["fear"], marker='o', markersize=7,label = "fear")
plt.plot(x_gra, y_gra["sadness"], marker='o', markersize=7,label = "sadness")
plt.plot(x_gra, y_gra["happiness"], marker='o', markersize=7,label = "happiness",linewidth = "7",color = "pink")
plt.tight_layout()
plt.legend()
plt.savefig("pics/pe_2.jpg")
plt.show()
print(x_gra,y_gra)
-
接受一个字典 dic,其中包含不同省份和情感类别的计数信息。
-
使用 Pyecharts 的 Line 组件生成省份-情感关系的折线图,使用 Map 和 Timeline 组件生成地理分布图。
词云图
wdc(str):
def wdc(str):
ls = jieba.lcut(str) # 生成分词列表
text = ' '.join(ls) # 连接成字符串
stopwords = ["我","你","她","的","是","了","在","也","和","就","都","这","啊啊啊"] # 去掉不需要显示的词
import numpy as np
from PIL import Image
mk = np.array(Image.open("wdbg.png"))
wc = wordcloud.WordCloud(font_path="msyh.ttc",
mask = mk,
width = 500,
height = 500,
background_color='white',
max_words=200,
stopwords=stopwords)
# msyh.ttc电脑本地字体,写可以写成绝对路径
wc.generate(text) # 加载词云文本
wc.to_file("pics/wdc.png") # 保存词云文件
-
该函数使用 jieba 进行中文分词,生成词云图。在生成词云时,去除了一些常见的停用词,并指定了字体、背景图等参数。
-
最后,将生成的词云图保存为图片文件。
主函数
fun(flname = 'result.csv'):
def fun(flname = 'result.csv'):
counts = {'happiness':0, 'like':0, 'anger':0, 'surprise':0, 'disgust':0, 'sadness':0,'fear':0}
lk_em = {'happiness':0, 'like':0, 'anger':0, 'surprise':0, 'disgust':0, 'sadness':0,'fear':0}
pe = { 'like':{
},'disgust':{
},'happiness':{
},'sadness':{
},'anger':{
},'surprise':{
},'fear':{
}}
str = ""
if flname == '':
flname = 'result2.csv'
f = open(flname, mode='r', encoding='utf-8')
flag = 0
for i in f.readlines():
if flag == 1:
emosplit(i,counts)
province(i,pe)
like_emo(i,lk_em)
str += i.split(',')[0]
flag = 1
# print(counts)
# print(lk_em)
# print(pe)
# print(str)
pe_graphic(pe)
emograpic(counts)
lk_em_graphic(lk_em)
wdc(str)
-
主要功能是读取指定的 CSV 文件(默认为 'result.csv'),对数据进行情感分析和可视化。
-
它使用上述的各个函数来生成多个图表,包括饼状图、雷达图、柱状图、点赞-情感关系图、省份-情感关系图和词云图。
-
在运行代码之前,请确保已经安装了所需的 Python 库,并替换相关路径和文件名为你实际的数据文件。这样,你就能更详细地了解代码的各个部分及其功能。
参考文献
- 【深度学习】详解TextCNN
- [NLP] 文本分类之TextCNN模型原理和实现(超详细)
- Python数据可视化:折线图、柱状图、饼图代码
- python绘制雷达图(详细)
- 【干货】Python:wordcloud库绘制词云图