如何使用 Node.js 创建情感分析应用程序?
情绪分析是一种自然语言处理技术,用于从文本数据中确定情绪。它通常用于了解客户需求、研究用户反馈中的产品情绪、决策制定等。
情绪分析的类型:
- 细粒度情绪分析:当我们希望结果中的极性精度时完成。在这种类型的分析中,我们将结果分为极性类别,例如非常消极、消极、积极、非常积极、中性。
- 基于情绪的情绪分析:这种类型的分析检测不同类型的情绪,如快乐、愤怒和悲伤。
- 基于方面的情感分析:如果我们想了解用户以正面或负面的方式提及的特定方面或特征,则使用这种类型的分析。例如,用户评论说笔记本电脑非常好,但电池很差,所以在这里我们基于方面的算法将能够确定对电池有负面评价,而不是整个产品。
方法:在本文中,我们将使用 node js 创建一个情感分析应用程序,该应用程序从用户反馈中分析文本数据,我们将使用细粒度和基于情感的情感分析方法来获取用户情感。我们将使用 AFINN(以负五(负)和正五(正)之间的整数评定的英语单词词典),它包含在自然库中,我们将作为 npm 包包含在我们的应用程序中。
下面是分步实现:
Node JS 安装:按照链接下载并安装 Node.js:下载 Node.js。我们将通过执行以下命令确保我们在系统中安装了节点:
node -v
第 1 步:创建一个单独的文件夹,并在终端或命令提示符的帮助下导航到该文件夹并移至该文件夹。
cd
第 2 步:通过在终端中键入以下命令来创建 package.json:
npm init -y
要了解有关 package.json 的更多信息,请单击此处。
第 3 步:安装以下依赖项。
- Express: Express 是一个最小且灵活的 Node.js Web 应用程序框架,它为 Web 和移动应用程序提供了一组强大的功能
- Natural:支持大多数 NLP 算法的 Node.js 包
- 停用词:停用词,Node.js 包,允许您从输入文本中去除停用词
npm install --save express natural stopword
项目结构:项目结构将如下所示:
第 4 步:首先,我们将创建一个基本的 HTTP 服务器。
server.js
// Import packages below
const express = require("express");
const natural = require("natural");
const stopword = require("stopword");
// Port and Host
const port = 5500;
const host = "127.0.0.1";
// Initialise our app
let app = express();
// Include Routes
// Listen
app.listen(port,host,()=>{
console.log("Server is running...");
});
server.js
// Include Routes
app.post("/feedback",(request,response)=>{
const { feedback } = request.body;
});
server.js
// Include npm packages
const express = require("express");
const natural = require("natural");
const stopword = require("stopword");
// For conversion of contractions to standard lexicon
const wordDict = {
"aren't": "are not",
"can't": "cannot",
"couldn't": "could not",
"didn't": "did not",
"doesn't": "does not",
"don't": "do not",
"hadn't": "had not",
"hasn't": "has not",
"haven't": "have not",
"he'd": "he would",
"he'll": "he will",
"he's": "he is",
"i'd": "I would",
"i'd": "I had",
"i'll": "I will",
"i'm": "I am",
"isn't": "is not",
"it's": "it is",
"it'll": "it will",
"i've": "I have",
"let's": "let us",
"mightn't": "might not",
"mustn't": "must not",
"shan't": "shall not",
"she'd": "she would",
"she'll": "she will",
"she's": "she is",
"shouldn't": "should not",
"that's": "that is",
"there's": "there is",
"they'd": "they would",
"they'll": "they will",
"they're": "they are",
"they've": "they have",
"we'd": "we would",
"we're": "we are",
"weren't": "were not",
"we've": "we have",
"what'll": "what will",
"what're": "what are",
"what's": "what is",
"what've": "what have",
"where's": "where is",
"who'd": "who would",
"who'll": "who will",
"who're": "who are",
"who's": "who is",
"who've": "who have",
"won't": "will not",
"wouldn't": "would not",
"you'd": "you would",
"you'll": "you will",
"you're": "you are",
"you've": "you have",
"'re": " are",
"wasn't": "was not",
"we'll": " will",
"didn't": "did not"
}
const port = 5500;
const host = "127.0.0.1";
let app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/",express.static(__dirname + "/public"));
// Contractions to standard lexicons Conversion
const convertToStandard = text => {
const data = text.split(' ');
data.forEach((word, index) => {
Object.keys(wordDict).forEach(key => {
if (key === word.toLowerCase()) {
data[index] = wordDict[key]
};
});
});
return data.join(' ');
}
// LowerCase Conversion
const convertTolowerCase = text => {
return text.toLowerCase();
}
// Pure Alphabets extraction
const removeNonAlpha = text => {
// This specific Regex means that replace all
//non alphabets with empty string.
return text.replace(/[^a-zA-Z\s]+/g, '');
}
// Analysis Route
app.post("/feedback", (request, response) => {
console.log(request.body);
// NLP Logic
// Convert all data to its standard form
const lexData = convertToStandard(request.body.feedback);
console.log("Lexed Data: ",lexData);
// Convert all data to lowercase
const lowerCaseData = convertTolowerCase(lexData);
console.log("LowerCase Format: ",lowerCaseData);
// Remove non alphabets and special characters
const onlyAlpha = removeNonAlpha(lowerCaseData);
console.log("OnlyAlpha: ",onlyAlpha);
// Tokenization
const tokenConstructor = new natural.WordTokenizer();
const tokenizedData = tokenConstructor.tokenize(onlyAlpha);
console.log("Tokenized Data: ",tokenizedData);
// Remove Stopwords
const filteredData = stopword.removeStopwords(tokenizedData);
console.log("After removing stopwords: ",filteredData);
// Stemming
const Sentianalyzer =
new natural.SentimentAnalyzer('English', natural.PorterStemmer, 'afinn');
const analysis_score = Sentianalyzer.getSentiment(filteredData);
console.log("Sentiment Score: ",analysis_score);
response.status(200).json({
message: "Data received",
sentiment_score: analysis_score
})
});
app.listen(port, host, () => {
console.log('Server is running...');
});
index.html
Event Feedback Application
Event Feedback ????
main.js
// Grab all HTML Elements
// All containers
const feedback = document.getElementById("feedbacktext");
const wholeContainer = document.querySelector(".feedback");
const resultContainer = document.querySelector(".results");
// All controls
const submit_button = document.getElementById("submit");
const closeButton = document.querySelector(".close");
// Results
const emoji = document.querySelector(".emoji");
const sentiment = document.querySelector(".sentiment");
// Add event listener to submit button, send feedback and
// name to our node js server application
submit_button.addEventListener("click",()=>{
console.log("Feedback: ",feedback.value);
// Send POST request to our server
const options = {
method : "POST",
body : JSON.stringify({
feedback : feedback.value
}),
headers : new Headers({
'Content-Type' : "application/json"
})
}
// Use fetch to request server
fetch("/feedback",options)
.then(res=>res.json())
.then((response)=>{
console.log(response.sentiment_score);
const score = response.sentiment_score;
// Separate responses according to sentiment_score
if(score > 0){
emoji.innerHTML = "😄
";
sentiment.innerHTML = "➕ Positive
";
}else if(score === 0){
emoji.innerHTML = "😐
";
sentiment.innerHTML = "Neutral
";
}else{
emoji.innerHTML = "😡
";
sentiment.innerHTML = "➖ Negative
";
}
// Result Box should appear
resultContainer.classList.add("active");
wholeContainer.classList.add("active");
})
.catch(err=>console.error("Error: ",err));
// Clear all inputs after operation
feedback.value = "";
});
// Close Button
closeButton.addEventListener("click",()=>{
wholeContainer.classList.remove("active");
resultContainer.classList.remove("active");
})
第 5 步:创建一个新路由并为其指定路径/feedback,当用户向我们的路由发送 POST 请求并在其请求正文中包含反馈时,他们应该会收到包含其情绪分析的响应。
服务器.js
// Include Routes
app.post("/feedback",(request,response)=>{
const { feedback } = request.body;
});
第 6 步:我们从用户那里获得的数据充满了许多错误和噪音,我们必须在分析过程中过滤掉这些错误和噪音。为了提取有意义的情感或信息,我们必须过滤用户的文本数据,这个过程称为数据过滤。
过滤步骤:
- 为了维护我们数据的结构,我们会将所有单词转换为其标准形式。例如,你是 -> 你是。
- 我们所有的文本数据都将小写 因为我们希望我们的分析算法将brilliant和BriLLiaNt视为同一个词。
- 删除特殊字符和数字标记,因为它们只是嘈杂的元素,它们对我们结果的贡献也将为空。
- 标记化是此过滤过程中的关键步骤之一,因为这是将文本拆分为有意义的单元的过程。我们将使用我们导入的 Natural 包中的 WordTokenizer。
- 移除停用词,因为这些词对用户的情绪没有任何贡献,停用词的一些示例包括:但是、a 或等。
- NLP中词归一化的过程,其中词干算法有望减少 词根词。例如“训练”,“训练”到“训练”。 Natural 库中的 Sentiment Analyzer 为我们提供了在调用它时提供一个词干分析器作为参数的选项。在其分析过程中,单个单词将被转换为它们的词根形式。
使用 Natural 的情绪分析: Natural 库中的情绪分析算法使用AFINN ,它是一个英语单词词典,以负五(负)和正五(正)之间的整数为价进行评级。计算一段文本中每个单词的极性之和,并用句子的长度对其进行归一化,这就是算法的工作原理。如果算法返回负值,则表示情绪是消极的,如果返回正值,则表示情绪是积极的。零值表示中性情绪。
我们将创建一条路线/反馈,我们将在其中收集用户的反馈并实施我们的分析。名为 convertToStandard 的函数会将我们所有的数据转换为其标准形式。 convertTolowerCase函数将我们所有的数据转换为小写形式。 removeNonAlpha函数将删除非字母。接下来,我们将使用 stopword npm 包标记我们的数据并删除停用词。在所有这些数据过滤代码之后,我们将使用一个自然包,来自 Natural 的 SentimentAnalyzer 将从我们的用户评论中创建一个情绪分数。最后,我们将根据我们的分析将此情绪得分发送给我们的用户。
服务器.js
// Include npm packages
const express = require("express");
const natural = require("natural");
const stopword = require("stopword");
// For conversion of contractions to standard lexicon
const wordDict = {
"aren't": "are not",
"can't": "cannot",
"couldn't": "could not",
"didn't": "did not",
"doesn't": "does not",
"don't": "do not",
"hadn't": "had not",
"hasn't": "has not",
"haven't": "have not",
"he'd": "he would",
"he'll": "he will",
"he's": "he is",
"i'd": "I would",
"i'd": "I had",
"i'll": "I will",
"i'm": "I am",
"isn't": "is not",
"it's": "it is",
"it'll": "it will",
"i've": "I have",
"let's": "let us",
"mightn't": "might not",
"mustn't": "must not",
"shan't": "shall not",
"she'd": "she would",
"she'll": "she will",
"she's": "she is",
"shouldn't": "should not",
"that's": "that is",
"there's": "there is",
"they'd": "they would",
"they'll": "they will",
"they're": "they are",
"they've": "they have",
"we'd": "we would",
"we're": "we are",
"weren't": "were not",
"we've": "we have",
"what'll": "what will",
"what're": "what are",
"what's": "what is",
"what've": "what have",
"where's": "where is",
"who'd": "who would",
"who'll": "who will",
"who're": "who are",
"who's": "who is",
"who've": "who have",
"won't": "will not",
"wouldn't": "would not",
"you'd": "you would",
"you'll": "you will",
"you're": "you are",
"you've": "you have",
"'re": " are",
"wasn't": "was not",
"we'll": " will",
"didn't": "did not"
}
const port = 5500;
const host = "127.0.0.1";
let app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/",express.static(__dirname + "/public"));
// Contractions to standard lexicons Conversion
const convertToStandard = text => {
const data = text.split(' ');
data.forEach((word, index) => {
Object.keys(wordDict).forEach(key => {
if (key === word.toLowerCase()) {
data[index] = wordDict[key]
};
});
});
return data.join(' ');
}
// LowerCase Conversion
const convertTolowerCase = text => {
return text.toLowerCase();
}
// Pure Alphabets extraction
const removeNonAlpha = text => {
// This specific Regex means that replace all
//non alphabets with empty string.
return text.replace(/[^a-zA-Z\s]+/g, '');
}
// Analysis Route
app.post("/feedback", (request, response) => {
console.log(request.body);
// NLP Logic
// Convert all data to its standard form
const lexData = convertToStandard(request.body.feedback);
console.log("Lexed Data: ",lexData);
// Convert all data to lowercase
const lowerCaseData = convertTolowerCase(lexData);
console.log("LowerCase Format: ",lowerCaseData);
// Remove non alphabets and special characters
const onlyAlpha = removeNonAlpha(lowerCaseData);
console.log("OnlyAlpha: ",onlyAlpha);
// Tokenization
const tokenConstructor = new natural.WordTokenizer();
const tokenizedData = tokenConstructor.tokenize(onlyAlpha);
console.log("Tokenized Data: ",tokenizedData);
// Remove Stopwords
const filteredData = stopword.removeStopwords(tokenizedData);
console.log("After removing stopwords: ",filteredData);
// Stemming
const Sentianalyzer =
new natural.SentimentAnalyzer('English', natural.PorterStemmer, 'afinn');
const analysis_score = Sentianalyzer.getSentiment(filteredData);
console.log("Sentiment Score: ",analysis_score);
response.status(200).json({
message: "Data received",
sentiment_score: analysis_score
})
});
app.listen(port, host, () => {
console.log('Server is running...');
});
第 7 步:为了将前端与我们的服务器连接,我们必须添加一行代码,该代码将添加到我们的 server.js 文件中,这意味着我们所有的静态 HTML、CSS 和 JS 文件都将在 /路线。
服务器.js
app.use("/",express.static(__dirname + "/public"));
现在,我们将创建一个名为 index.html 的 HTML 文件,作为我们的前端。
索引.html
Event Feedback Application
Event Feedback ????
第 8 步:现在在 /public 文件夹中,让我们创建一个名为 main.js 的文件,我们将在其中添加一些用于进行 API 调用的函数。抓取所有 HTML 元素。所以我们的逻辑是,当我们的用户填写反馈表单时,点击提交后,应该调用一个函数,并且应该对我们的 node js 服务器进行 API 调用。我们将在我们的按钮上添加一个点击事件,点击后,我们将对我们的服务器进行 API 调用,我们将根据我们的反馈得到响应。根据我们的情绪得分,我们将使用表情符号显示我们的结果。
main.js
// Grab all HTML Elements
// All containers
const feedback = document.getElementById("feedbacktext");
const wholeContainer = document.querySelector(".feedback");
const resultContainer = document.querySelector(".results");
// All controls
const submit_button = document.getElementById("submit");
const closeButton = document.querySelector(".close");
// Results
const emoji = document.querySelector(".emoji");
const sentiment = document.querySelector(".sentiment");
// Add event listener to submit button, send feedback and
// name to our node js server application
submit_button.addEventListener("click",()=>{
console.log("Feedback: ",feedback.value);
// Send POST request to our server
const options = {
method : "POST",
body : JSON.stringify({
feedback : feedback.value
}),
headers : new Headers({
'Content-Type' : "application/json"
})
}
// Use fetch to request server
fetch("/feedback",options)
.then(res=>res.json())
.then((response)=>{
console.log(response.sentiment_score);
const score = response.sentiment_score;
// Separate responses according to sentiment_score
if(score > 0){
emoji.innerHTML = "😄
";
sentiment.innerHTML = "➕ Positive
";
}else if(score === 0){
emoji.innerHTML = "😐
";
sentiment.innerHTML = "Neutral
";
}else{
emoji.innerHTML = "😡
";
sentiment.innerHTML = "➖ Negative
";
}
// Result Box should appear
resultContainer.classList.add("active");
wholeContainer.classList.add("active");
})
.catch(err=>console.error("Error: ",err));
// Clear all inputs after operation
feedback.value = "";
});
// Close Button
closeButton.addEventListener("click",()=>{
wholeContainer.classList.remove("active");
resultContainer.classList.remove("active");
})
运行应用程序的步骤:要启动此应用程序,请在命令提示符处执行以下命令:
node server.js
输出:导航到 http://localhost:5500/
服务器日志: