情感分析(又称为观点挖掘或感情AI)是一种利用自然语言处理、文本分析、计算语言学等技术来系统地识别、提取、量化和研究情感状态和主观信息的方法。
应用领域:
1.社交媒体分析:企业通过分析消费者在社交媒体上的情感反馈,了解消费者对产品或服务的态度和偏好,从而把握市场需求,调整产品或服务策略,提高市场竞争力。
2.产品评价:电商平台利用情感分析技术自动分析用户评价,识别用户的积极或消极情感,为其他消费者提供参考,同时也为商家提供产品改进的建议。
3.心理健康评估:识别和分析患者的情感状态,如抑郁、焦虑等,为医生提供诊断和治疗方案制定的辅助工具。
4.情感管理:个人可以利用情感分析技术来分析自己在社交媒体上的情感反馈,了解自己的情感状态和情感偏好,有助于更好地管理情绪和心理健康。
5.影视评论分析:在电影、电视剧等媒体产品的评论分析中,情感分析技术可以帮助制片方了解观众的情感反馈,优化内容制作。
容器情感分析是指将做情感分析所需要的环境依赖、以及可视化打包到镜像当中,方便我们在各种操作系统下运行。
主要是利用python中的NLTK(Natural Language Toolkit)自然语言处理(NLP)的 Python 库加Falsk的PythonWeb框架来完成后端的部署
##关于NLTK部分:
1. 文本处理功能
分词(Tokenization):将文本分割成单词或句子。
词性标注(Part-of-Speech Tagging):为文本中的单词标注词性(如名词、动词等)。
2. 语言资源
语料库(Corpora):NLTK 提供了许多用于研究的语料库,如《爱丽丝梦游仙境》的文本、电影评论等。
词典(Lexicons):包括情感词典(如 SentiWordNet)、同义词词典(如 WordNet)等。
3. 文本分析工具
情感分析(Sentiment Analysis):使用诸如 VADER、TextBlob 等工具分析文本情感。
词汇分析:统计词频、计算文本相似度等。
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
import matplotlib.pyplot as plt
from nltk.sentiment.vader import SentimentIntensityAnalyzer
##处理文本方法:将一段完整的话拆分成单独的单词,再将其中一些人称代词(I、you、she)、系动词(am、is、are)、介词(to)、连词(so、but)进行过滤。最后得到形容词与动词
def preprocess_text(text):
stop_words = set(stopwords.words('english'))
word_tokens = word_tokenize(text)
filtered_text = [word for word in word_tokens if word.lower() not in stop_words and word.isalpha()]
return ' '.join(filtered_text)
##计算情感值方法:将过滤后的形容词与动词进行计算,比如正面的与负面进行抵消
def analyze_sentiment_vader(text):
analyzer = SentimentIntensityAnalyzer()
sentiment = analyzer.polarity_scores(text)['compound']
return sentiment
##展示可视化情感值图方法:将计算的结果,使用matplotlib库展示出来
def visualize_comparison(sentiment_score_vader):
plt.bar(['VADER'], [sentiment_score_vader], color=['blue'])
plt.ylim(-1, 1)
plt.ylabel('Sentiment Score')
plt.title('Sentiment Analysis Comparison')
plt.show()
# 示例文本
text = "I'm happy to see you ! but I'm sad that you have to leave."
processed_text = preprocess_text(text)
print("Processed Text:", processed_text)
sentiment_score_vader = analyze_sentiment_vader(processed_text)
print("Sentiment Score (VADER):", sentiment_score_vader)
visualize_comparison(sentiment_score_vader)
运行结果:
根据计算的情感值我们大致将它分成三类:
根据这三种情感,我们在前端页面中展示出来
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js"></script>
<style>
body{
background-color: firebrick;
}
#All{
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.inputT{
margin-top: 100px;
width: 750px;
height: 200px;
/* border-left: 1px solid ;
border-bottom: 1px solid white; */
border-top: 1px solid white;
border-bottom: 1px solid white;
border-left: 0;
border-right: 0;
color: brown;
font-size: 40px;
}
#but_area{
display: flex;
align-items: center;
margin-top: 15px;
}
#but{
color: white;
font-size: 50px;
}
#res_area{
margin-top: 35px;
height: 300px;
width: 300px;
/* border: solid 1px; */
display: flex;
align-items: center;
justify-content: center;
}
</style>
<body>
<div id="All">
<input class="inputT" type="text" v-model="value" name="value"/>
<div id="but_area">
//两个svg图表,不用管
<svg t="1721048140169" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3728" width="200" height="200"><path d="M239.274 764.996h106.952v88h-106.952zM559.564 554h149.31v128.688h-149.31z" fill="#DBADA2" p-id="3729"></path><path d="M730.436 682.688h-192.45c-11.782 0-21.328 9.528-21.328 21.308v319.996h235.12V703.996c0-11.782-9.562-21.308-21.342-21.308z" fill="#ED5564" p-id="3730"></path><path d="M870.308 308.05c-12.5-12.5-32.75-12.5-45.25 0l-148.184 158.388L783.402 512l88.968-151.998c9.376-17.294 10.438-39.466-2.062-51.952z" fill="#DBADA2" p-id="3731"></path><path d="M516.658 703.996v64h235.12v-64c0-11.782-9.56-21.308-21.342-21.308h-192.45c-11.78 0-21.328 9.526-21.328 21.308z" fill="#DA4453" p-id="3732"></path><path d="M346.584 853.308h-107.108c-11.782 0-21.344 9.562-21.344 21.376v149.308h149.794v-149.308c0.002-11.812-9.546-21.376-21.342-21.376z" fill="#5D9CEC" p-id="3733"></path><path d="M218.132 874.684v21.308h149.794v-21.308c0-11.812-9.546-21.376-21.344-21.376h-107.108c-11.778 0-21.342 9.564-21.342 21.376z" fill="#4A89DC" p-id="3734"></path><path d="M762.214 42.68c-17.686 0-31.998 14.328-31.998 32v202.652a10.674 10.674 0 0 1-10.654 10.672 10.68 10.68 0 0 1-10.688-10.672V32.008c0-17.672-14.312-32-32-32-17.656 0-32 14.328-32 32v245.324a10.652 10.652 0 0 1-10.654 10.672 10.672 10.672 0 0 1-10.656-10.672V74.68c0-17.672-14.344-32-32-32-17.688 0-32 14.328-32 32v202.652a10.68 10.68 0 0 1-10.688 10.672 10.664 10.664 0 0 1-10.656-10.672V160.006c0-17.672-14.328-32-32-32-17.686 0-32 14.328-32 32v298.666c0 88.358 71.624 160.014 159.998 160.014 88.372 0 159.994-71.656 159.994-160.014V74.68c0.002-17.672-14.31-32-31.998-32zM207.696 426.33c-11.782 0-21.328 9.562-21.328 21.344V597h42.67v-149.328c0.002-11.78-9.562-21.342-21.342-21.342zM261.04 383.674c-11.796 0-21.344 9.546-21.344 21.328V597h42.67v-191.998c0-11.78-9.546-21.328-21.326-21.328zM314.366 426.33c-11.782 0-21.328 9.562-21.328 21.344V597h42.656v-149.328c0-11.78-9.546-21.342-21.328-21.342z" fill="#EAC6BB" p-id="3735"></path><path d="M149.948 624.562c-8.328 8.344-6.25 17.75 0 30.188l43.42 91.34 71.016-37.25-84.264-84.278c-8.328-8.312-21.844-8.312-30.172 0z" fill="#DBADA2" p-id="3736"></path><path d="M367.694 469c-11.782 0-21.328 9.546-21.328 21.328v149.358h42.672v-149.358c0-11.78-9.564-21.328-21.344-21.328z" fill="#EAC6BB" p-id="3737"></path><path d="M389.038 708.996c0 55.968-45.376 101.312-101.342 101.312s-101.326-45.344-101.326-101.312c0-55.964 45.358-101.308 101.326-101.308s101.342 45.344 101.342 101.308z" fill="#EAC6BB" p-id="3738"></path><path d="M186.368 597h202.668v111.996H186.368z" fill="#EAC6BB" p-id="3739"></path></svg>
//在这里实现提交请求
<div id="but" @click="submit">点击这里</div>
<svg t="1721048140169" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3728" width="200" height="200"><path d="M239.274 764.996h106.952v88h-106.952zM559.564 554h149.31v128.688h-149.31z" fill="#DBADA2" p-id="3729"></path><path d="M730.436 682.688h-192.45c-11.782 0-21.328 9.528-21.328 21.308v319.996h235.12V703.996c0-11.782-9.562-21.308-21.342-21.308z" fill="#ED5564" p-id="3730"></path><path d="M870.308 308.05c-12.5-12.5-32.75-12.5-45.25 0l-148.184 158.388L783.402 512l88.968-151.998c9.376-17.294 10.438-39.466-2.062-51.952z" fill="#DBADA2" p-id="3731"></path><path d="M516.658 703.996v64h235.12v-64c0-11.782-9.56-21.308-21.342-21.308h-192.45c-11.78 0-21.328 9.526-21.328 21.308z" fill="#DA4453" p-id="3732"></path><path d="M346.584 853.308h-107.108c-11.782 0-21.344 9.562-21.344 21.376v149.308h149.794v-149.308c0.002-11.812-9.546-21.376-21.342-21.376z" fill="#5D9CEC" p-id="3733"></path><path d="M218.132 874.684v21.308h149.794v-21.308c0-11.812-9.546-21.376-21.344-21.376h-107.108c-11.778 0-21.342 9.564-21.342 21.376z" fill="#4A89DC" p-id="3734"></path><path d="M762.214 42.68c-17.686 0-31.998 14.328-31.998 32v202.652a10.674 10.674 0 0 1-10.654 10.672 10.68 10.68 0 0 1-10.688-10.672V32.008c0-17.672-14.312-32-32-32-17.656 0-32 14.328-32 32v245.324a10.652 10.652 0 0 1-10.654 10.672 10.672 10.672 0 0 1-10.656-10.672V74.68c0-17.672-14.344-32-32-32-17.688 0-32 14.328-32 32v202.652a10.68 10.68 0 0 1-10.688 10.672 10.664 10.664 0 0 1-10.656-10.672V160.006c0-17.672-14.328-32-32-32-17.686 0-32 14.328-32 32v298.666c0 88.358 71.624 160.014 159.998 160.014 88.372 0 159.994-71.656 159.994-160.014V74.68c0.002-17.672-14.31-32-31.998-32zM207.696 426.33c-11.782 0-21.328 9.562-21.328 21.344V597h42.67v-149.328c0.002-11.78-9.562-21.342-21.342-21.342zM261.04 383.674c-11.796 0-21.344 9.546-21.344 21.328V597h42.67v-191.998c0-11.78-9.546-21.328-21.326-21.328zM314.366 426.33c-11.782 0-21.328 9.562-21.328 21.344V597h42.656v-149.328c0-11.78-9.546-21.342-21.328-21.342z" fill="#EAC6BB" p-id="3735"></path><path d="M149.948 624.562c-8.328 8.344-6.25 17.75 0 30.188l43.42 91.34 71.016-37.25-84.264-84.278c-8.328-8.312-21.844-8.312-30.172 0z" fill="#DBADA2" p-id="3736"></path><path d="M367.694 469c-11.782 0-21.328 9.546-21.328 21.328v149.358h42.672v-149.358c0-11.78-9.564-21.328-21.344-21.328z" fill="#EAC6BB" p-id="3737"></path><path d="M389.038 708.996c0 55.968-45.376 101.312-101.342 101.312s-101.326-45.344-101.326-101.312c0-55.964 45.358-101.308 101.326-101.308s101.342 45.344 101.342 101.308z" fill="#EAC6BB" p-id="3738"></path><path d="M186.368 597h202.668v111.996H186.368z" fill="#EAC6BB" p-id="3739"></path></svg>
</div>
<div id="res_area">
<img :src="img" alt="" />
</div>
</div>
</body>
<script>
var demo = new Vue({
el: "#All",
data: {
end_res: null,
img: "./images/neu0.png", //当前表情为中性表情
pos:["./images/pos0.png","./images/pos1.png","./images/pos2.png"], //积极表情
neg:["./images/neg0.png","./images/neg1.png","./images/neg2.png"] //消极表情
},
methods: {
submit: function() {
//获取input的值
var value = document.getElementsByClassName('inputT')[0].value;
console.log(value);
//提交请求
fetch('http://127.0.0.1:5000/Computed', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ value: value })
})
//获取后端返回数据
.then(response => response.json())
.then(data => {
console.log(data);
this.end_res = data; // 使用 Vue 的方法来更新数据
this.change_src(this.end_res)
})
.catch(error => {
console.error('Error:', error);
});
},
//修改图片路径
change_src:function(end_res){
if(end_res==1){
var randomInt = this.getRandomIntInclusive(0, 2);
this.img = this.pos[randomInt]
}
else if(end_res==2){
var randomInt = this.getRandomIntInclusive(0, 2);
this.img = this.neg[randomInt]
}
else{
this.img = "./images/neu0.png"
}
},
//随机一个0到2的随机数
getRandomIntInclusive:function(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
});
</script>
</html>
from flask import Flask, request, jsonify
from flask_cors import CORS
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.sentiment.vader import SentimentIntensityAnalyzer
# 指定本地 NLTK 数据目录
nltk.data.path.append('F:/nltk_data')
def preprocess_text(text):
stop_words = set(stopwords.words('english'))
word_tokens = word_tokenize(text)
filtered_text = [word for word in word_tokens if word.lower() not in stop_words and word.isalpha()]
return ' '.join(filtered_text)
def analyze_sentiment_vader(text):
analyzer = SentimentIntensityAnalyzer()
sentiment = analyzer.polarity_scores(text)['compound']
return sentiment
#将情感值分类
def emotional_division(sentiment_score_vader):
if(sentiment_score_vader > 0.25):
return 1
elif(sentiment_score_vader < -0.25):
return 2
else:
return 0
app = Flask(__name__)
CORS(app)
@app.route('/Computed', methods=['POST'])
def get_text():
#获取前端传输的值
value = request.json
value = value['value']
print(f"Received text: {value}")
processed_text = preprocess_text(value)
print("processed_text:", processed_text)
sentiment_score_vader = analyze_sentiment_vader(processed_text)
print("sentiment_score_vader:", sentiment_score_vader)
res = emotional_division(sentiment_score_vader)
print("res:", res)
return jsonify(res)
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0', port=5000)
#启动一个本地开发服务器,
https://gitee.com/chenl16/sentiment-analysis_container.git
在此项目中,主要的环境有:Python、Flask库、NLTK库、web服务器
##构建方法
docker build -t sa:v1.0 .
##注意,该git中没有nltk_data.zip,需要下载nltk_data,然后将里面的packages重命名为nltk_data
docker run -itd --name sa -p 99:80 -p 5000:5000 sa:v1.0
运行案例:
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。