情绪理解是文本处理里最常见任务之一。现提供一个五类情绪字典(由情绪词组成,5个文件,人工标注),实现一个情绪分析工具,并利用该工具对10000条新浪微博进行测试和分析(一行一条微博)。微博数据见课程中心weibo.txt,字典数据见公开数据中的emotion lexicon
(https://doi.org/10.6084/m9.figshare.12163569.v2)。请按要求用函数进行功能封装,并在main中调用测试,鼓励尝试不同方式的可视化。
1. 实现一个函数,对微博数据进行清洗,去除噪声(如url等),过滤停用词。注意分词的
时候应该将情绪词典加入Jieba的自定义词典,以提高这些情绪词的识别能力。
2.实现两个函数,实现一条微博的情绪分析,返其情绪向量或情绪值。目前有两种方法,一是认为一条微博的情绪是混合的,即一共有n个情绪词,如果joy有n1个,则joy的比例是 n1/n;二是认为一条微博的情绪是唯一的,即n个情绪词里,anger的情绪词最多,则该微博的情绪应该为anqrv。注意,这里要求用闭包实现,尤其是要利用闭包实现一次加载情绪词典且局部变量持久化的特点。同时,也要注意考虑一些特别的情况,如无情绪词出现,不同情绪的情绪词出现数目一样等,并予以处理(如定义为无情绪,便于在后面的分析中去除)。
3、微博中包含时间,可以讨论不同时间情绪比例的变化趋势,实现一个函数,可以通过参数来控制并返回对应情绪的时间模式,如joy的小时模式,sadness的周模式等。
4.微博中包含空间,可可以讨论情绪的空间分布,实现一个函数,可以通过参数来控制并返回对应情绪的空间分布,即围绕某个中心点,随着半径增加该情绪所占比例的变化,中心点可默认值可以是城市的中心位置。
5. (附加)讨论字典方法进行情绪理解的优缺点,有无可能进一步扩充字典来提高情绪识别的准确率?
6. (附加)可否对情绪的时间和空间分布进行可视化?(如通过matplotlib绘制曲线,或者用pyecharts(注意版本的兼容性)在地图上标注不同的情绪)
7.(附加)思考情绪时空模式的管理意义?
目录

import jieba
import matplotlib.pyplot as plt
import re
import easygui as g
from pyecharts.charts import Geo
from pyecharts import options as opts
from pyecharts.globals import GeoType
def Emo_list():
'''这是将存储情绪词的文件路径变成列表'''
path1 = "D:/学习文件/大三上/现代程序设计/第二次作业/emotion_lexicon/anger.txt"
path2 = "D:/学习文件/大三上/现代程序设计/第二次作业/emotion_lexicon/disgust.txt"
path3 = "D:/学习文件/大三上/现代程序设计/第二次作业/emotion_lexicon/fear.txt"
path4 = "D:/学习文件/大三上/现代程序设计/第二次作业/emotion_lexicon/joy.txt"
path5 = "D:/学习文件/大三上/现代程序设计/第二次作业/emotion_lexicon/sadness.txt"
emotion_path = [path1,path2,path3,path4,path5]
return emotion_path
def add_word(emotion_path):
'''这是将情绪词加入jieba库,增加分词的可信力'''
for i in emotion_path:
jieba.load_userdict(i)
def Read_txt():
'''读入微博评论,按行存入列表'''
with open("D:\学习文件\大三上\现代程序设计\第二次作业\weibo1.txt",'r',encoding='utf-8') as f:
comments = f.read().splitlines()
return comments
def Clean_txt(comments):
'''这是对微博评论进行清洗,去除一些无意义的数据'''
#path是提前定义的,清洗后评论文件存放的地址
path = "D:/学习文件/大三上/现代程序设计/第二次作业/after_clean3.txt"
for com in comments: #对评论列表进行遍历
com = re.sub(r"(回复)?(//)?\s*@\S*?\s*(:| |$)", " ", com) # 去除正文中的@和回复/转发中的用户名
com = re.sub(r"\[\S+\]", "", com) # 去除表情符号
# com = re.sub(r"#\S+#", "", com) # 保留话题内容
URL_REGEX = re.compile(
r'(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))',re.IGNORECASE)
com = re.sub(URL_REGEX, "", com) # 去除网址
com = com.replace("我在:", "") # 去除无意义的词语
com = com.replace("我在这里:","")
com = re.sub(r"\s+", " ", com) # 合并正文中过多的空格
#将每一行清洗后评论写入path路径
after_clean = open(path,'a',encoding='utf-8')
after_clean.write(com+'\n')
return path
def Label_comment(path,emotion_path):
'''提取出每条评论的情绪、时间、地点。其中使用了闭包函数'''
emotions_list = [] #一个二维列表
for i in range(5):
with open(emotion_path[i],'r',encoding='utf-8') as f:
x= f.read().splitlines() #按行分词将文件变成列表
emotions_list.append(x)
#Cut()为内嵌函数
def Cut():
nonlocal emotions_list #将之前生成了情绪列表传入
nonlocal path #将清洗好的评论文件路径传入
#按path路径读入清洗后的评论文件
with open(path,'r',encoding='utf-8') as f:
comments = f.read().splitlines()
location = [] #存放经纬度列表
time = [] #存放时间的列表
emotion = [] #存放情绪的列表
for com in comments: #对评论进行遍历
emo_dict = {'anger':0,'disgust':0,'fear':0,'joy':0 ,'sadness':0} #对每条评论创建一个初始情绪字典
t = com[-30:] #时间为一条评论的后30个字符
a = com.index(']') #对‘]’进行定位
l = com[1:a] #l为储存经纬度
time.append(t) #往时间列表中加入t
location.append(l) #往经纬度列表中加入l
sentence = com[a+1:-30] #为评论的正文
#print(sentence)
words = jieba.lcut(sentence) #用jieba库进行分词
#依次对其在不同情绪字典中进行判断
for word in words:
if word in emotions_list[0]:
emo_dict['anger'] += 1
elif word in emotions_list[1]:
emo_dict['disgust'] += 1
elif word in emotions_list[2]:
emo_dict['fear'] += 1
elif word in emotions_list[3]:
emo_dict['joy'] += 1
elif word in emotions_list[4]:
emo_dict['sadness'] += 1
else:
pass
#找出字典中对应最大的值,所对应的键,作为该条评论情绪标签
emotion.append(max(emo_dict,key = emo_dict.get))
return emotion,location,time
return Cut
def time_plot(emotion,time):
'''通过参数来控制并返回对应情绪的时间模式,其中我们要选择情绪标签和时间周期两个参数'''
#使用easygui库来实现Gui的可视化参数选择
emo = g.buttonbox("选择一个要分析的情绪",choices = ('anger','disgust','fear','joy','sadness'))
trend = g.buttonbox('选择分析的时间趋势',choices = ('hour','month','week'))
n = len(emotion) #n = len(emotion) = len(location) = len(time)
#对time中的数据进行进一步的切割
weeks = [i[0:3] for i in time]
months = [i[4:7] for i in time]
hours = [i[11:13] for i in time]
#创建星期字典
week_dict = {'Mon':0,'Tue':0,'Wed':0,'Thu':0,'Fri':0,'Sat':0,'Sun':0}
#创建月份字典
month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
month_dict = {}
month_dict = month_dict.fromkeys(month,0)
#创建小时字典
hour_dic = ['{:0>2d}'.format(i) for i in range(1,25)] #format的使用是为了两位对齐
hour_dict = {}
hour_dict = hour_dict.fromkeys(hour_dic,0)
#根据所选trend参数来绘制不同的图形
if trend == 'hour':
for i in range(n):
if emo == emotion[i] and hours[i] in hour_dic: #emo为所选情绪参数
hour_dict[hours[i]] += 1
#由情绪字典绘图
x = list(hour_dict.values())
y = list(hour_dict.keys())
plt.plot(y,x)
plt.xlabel("hours")#横坐标名字
plt.ylabel("times")#纵坐标名字
plt.legend(loc = "best")#图例
elif trend == 'month':
for i in range(n):
if emo == emotion[i] and months[i] in ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']: #emo为所选参数
month_dict[months[i]] += 1
#由情绪字典绘图
x = list(month_dict.values())
y = list(month_dict.keys())
plt.plot(y,x)
plt.xlabel("months")#横坐标名字
plt.ylabel("times")#纵坐标名字
plt.legend(loc = "best")#图例
else:
for i in range(n):
if emo == emotion[i] and weeks[i] in ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']: #emo为所选参数
month_dict[weeks[i]] +=1
#由情绪字典绘图
x = list(week_dict.values())
y = list(week_dict.keys())
plt.plot(y,x)
plt.xlabel("weeks")#横坐标名字
plt.ylabel("times")#纵坐标名字
plt.legend(loc = "best")#图例
def Distance(location,emotion,limit):
'''这是显示距离中心距离内的情绪占比图'''
certen = [39.90,116.38] #定义北京天安门为中心
#初始定义一个情绪字典
emo_dict = {'anger':0,'disgust':0,'fear':0,'joy':0,'sadness':0}
n = len(location) #n = len(emotion) = len(location) = len(time)
for i in range(n):
a,b = location[i].split(',')
a = eval(a);b = eval(b) #a是维度,b是经度
distance = ((a-certen[0])**2+(b-certen[1])**2)**0.5 #计算两点的直线距离
if limit >= distance: #距离需要小于等于限制值
emo_dict[emotion[i]] += 1
#由情绪字典绘制饼图
label = list(emo_dict.keys())
size = list(emo_dict.values())
plt.pie(size,labels=label,shadow=True)
def test_geo(emotion,location):
'''在北京地图对情绪的空间分布进行可视化'''
emo = {'sadness':5,'joy':15,'fear':25,'disgust':35,'anger':45}
g = Geo()
data_pair = []
g.add_schema(maptype='北京')
for k in range(len(emotion)):
a,b = location[k].split(',')
a = eval(a);b = eval(b)
data_pair.append((emotion[k]+str(k),emo[emotion[k]]))
#print(type(address_list[k]))
g.add_coordinate(emotion[k]+str(k),b,a)
# 定义坐标对应的名称,添加到坐标库中 add_coordinate(name, lng, lat)
# 将数据添加到地图上
#print(data_pair)
g.add('', data_pair, type_=GeoType.EFFECT_SCATTER, symbol_size=5)
# 设置样式
g.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
# 自定义分段 color 可以用取色器取色
pieces = [
{'min': 1, 'max': 10, 'label': 'sadness', 'color': '#3700A4'},
{'min': 10, 'max': 20, 'label': 'joy', 'color': '#81AE9F'},
{'min': 20, 'max': 30, 'label': 'fear', 'color': '#E2C568'},
{'min': 30, 'max': 40, 'label': 'disgust', 'color': '#FCF84D'},
{'min': 40, 'max': 50, 'label': 'anger', 'color': '#DD0200'}
]
# is_piecewise 是否自定义分段, 变为true 才能生效
g.set_global_opts(
visualmap_opts=opts.VisualMapOpts(is_piecewise=True, pieces=pieces),
title_opts=opts.TitleOpts(title="北京市-情绪分布地图"),
)
return g
def main():
emotion_path = Emo_list()
add_word(emotion_path) #给jieba库加词
comments = Read_txt()
path = Clean_txt(comments)
#下面两行为闭包函数的调用
f1 = Label_comment(path, emotion_path)
emotion,location,time = f1()
#time_plot(emotion,time)
limit = 1
#limit = eval(input("请输入限制距离大小:"))
Distance(location,emotion,limit)
#pyechars绘制北京地图
test_geo(emotion,location)
g.render('beijing.html') # 渲染成html, 可用浏览器直接打开
if __name__ == '__main__':
main()

可以看到清洗之后的评论,少了很多url,还有⼀些重复⽤语。
情绪列表

时间列表

地点列表(经纬度)





我们发现,该微博数据集数据主要分布在北京的主城区
感觉单纯⽤分词对⼀句话进⾏分类会显得很单薄,中国⼈说话可能很委婉。同时,还有⼀些⼈正话反说,这会导致极⼤的误差
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些
我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。