📜  如何使用 Node.js 创建情感分析应用程序?

📅  最后修改于: 2022-05-13 01:56:22.917000             🧑  作者: Mango

如何使用 Node.js 创建情感分析应用程序?

情绪分析是一种自然语言处理技术,用于从文本数据中确定情绪。它通常用于了解客户需求、研究用户反馈中的产品情绪、决策制定等。

情绪分析的类型:

  1. 细粒度情绪分析:当我们希望结果中的极性精度时完成。在这种类型的分析中,我们将结果分为极性类别,例如非常消极、消极、积极、非常积极、中性。
  2. 基于情绪的情绪分析:这种类型的分析检测不同类型的情绪,如快乐、愤怒和悲伤。
  3. 基于方面的情感分析:如果我们想了解用户以正面或负面的方式提及的特定方面或特征,则使用这种类型的分析。例如,用户评论说笔记本电脑非常好,但电池很差,所以在这里我们基于方面的算法将能够确定对电池有负面评价,而不是整个产品。

方法:在本文中,我们将使用 node js 创建一个情感分析应用程序,该应用程序从用户反馈中分析文本数据,我们将使用细粒度和基于情感的情感分析方法来获取用户情感。我们将使用 AFINN(以负五(负)和正五(正)之间的整数评定的英语单词词典),它包含在自然库中,我们将作为 npm 包包含在我们的应用程序中。

下面是分步实现:

Node JS 安装:按照链接下载并安装 Node.js:下载 Node.js。我们将通过执行以下命令确保我们在系统中安装了节点:

node -v

第 1 步:创建一个单独的文件夹,并在终端或命令提示符的帮助下导航到该文件夹并移至该文件夹。

cd 

第 2 步:通过在终端中键入以下命令来创建 package.json:

npm init -y

要了解有关 package.json 的更多信息,请单击此处
第 3 步:安装以下依赖项。  

  1. Express: Express 是一个最小且灵活的 Node.js Web 应用程序框架,它为 Web 和移动应用程序提供了一组强大的功能
  2. Natural:支持大多数 NLP 算法的 Node.js 包
  3. 停用词停用词,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



    
    
        
            
            
            
            
            
                             
        
    
              


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 步:我们从用户那里获得的数据充满了许多错误和噪音,我们必须在分析过程中过滤掉这些错误和噪音。为了提取有意义的情感或信息,我们必须过滤用户的文本数据,这个过程称为数据过滤。

过滤步骤:

  1. 为了维护我们数据的结构,我们会将所有单词转换为其标准形式。例如,你是 -> 你是。
  2. 我们所有的文本数据都将小写 因为我们希望我们的分析算法将brilliantBriLLiaNt视为同一个词。
  3. 删除特殊字符和数字标记,因为它们只是嘈杂的元素,它们对我们结果的贡献也将为空。
  4. 标记化是此过滤过程中的关键步骤之一,因为这是将文本拆分为有意义的单元的过程。我们将使用我们导入的 Natural 包中的 WordTokenizer。
  5. 移除停用词,因为这些词对用户的情绪没有任何贡献,停用词的一些示例包括:但是、a 或等。
  6. 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



    
    
        
            
            
            
            
            
                             
        
    
              

第 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/

活动反馈

服务器日志: