Building a sentiment analysis app with Node.js

2025-06-08

使用 Node.js 构建情绪分析应用程序

作者:Ebenezer Don✏️

在这篇文章中,我们将使用 Node.js 构建一个情绪分析应用程序,该应用程序分析来自用户评论的文本数据,并使用自然语言处理 (NLP) 来确定用户的情绪。

我们的最终应用程序将如下所示:

情绪分析应用预览

在开始之前,让我们先了解一下情感分析和自然语言处理的含义。

什么是情绪分析?

情绪分析是分析文本数据并得出其情绪基调的过程。例如,将顾客对产品的评价分为满意、不满意或中性。为了自动化这一过程,我们将使用自然语言处理(人工智能的一个分支)。

什么是自然语言处理?

与编程语言不同,自然语言通常具有歧义性,并且并非设计为计算机可理解的——因此需要一种技术来处理自然语言,以便从中获取有意义且可操作的数据。SAS 对此进行了简洁的阐述:

自然语言处理是人工智能的一个分支,它使计算机能够解释、从人类语言中获取含义并操纵人类语言。

LogRocket 免费试用横幅

设置

让我们首先使用 Express 框架构建一个新的 Node.js 应用程序。我们将使用express-generatorCLI 工具生成一个脚手架应用程序。

首先,我们将通过在终端上运行以下命令来确保已安装 Node:

node --version
Enter fullscreen mode Exit fullscreen mode

如果返回错误消息,请点击此处查看 Node 安装说明。安装 Node 后,我们在终端上运行以下命令:

npm install -g express-generator
Enter fullscreen mode Exit fullscreen mode

express-generator就是我们将用来搭建一个新的 Node 应用的脚本。为此,我们将运行:

express node_nlp --no-view
Enter fullscreen mode Exit fullscreen mode

要启动我们的应用程序,让我们导航到新的应用程序目录并运行npm start

cd node_nlp
npm start
Enter fullscreen mode Exit fullscreen mode

在新生成的应用目录中,导航到./package.json。我们需要设置 nodemon,以便在保存新更改时自动重启应用程序。在终端上运行:

npm install --save nodemon
Enter fullscreen mode Exit fullscreen mode

接下来,我们将添加一个新脚本,通过 nodemon 启动我们的应用程序。在 下scriptspackage.json添加以下代码:

"dev": "nodemon ./bin/www"
Enter fullscreen mode Exit fullscreen mode

接下来,我们可以通过在终端上运行以下命令来启动我们的应用程序:

npm run dev
Enter fullscreen mode Exit fullscreen mode

现在我们已经成功设置了我们的应用程序,让我们使用 NLP 实现我们的情绪分析功能。

我们首先安装Natural,这是一个 Node.js 包,它支持我们项目中使用的大多数 NLP 算法。我们在终端上运行以下命令:

npm install --save natural
Enter fullscreen mode Exit fullscreen mode

接下来,在我们的routes目录中,我们将创建一个新文件并将其命名为nlp.js。我们将在这里存放与NLP相关的路由API。在我们的新文件,,./routes/nlp.js让我们导入以下包:

const express = require('express');
const natural = require('natural');
Enter fullscreen mode Exit fullscreen mode

之后,我们将创建一个新的路由并赋予其路径s-analyzer。当用户POST向我们的路由发送请求时,在请求主体中包含产品评论,他们应该收到包含其情绪分析的响应。

为了创建新路线,让我们修改./routes/nlp.js文件:

const express = require('express');
const natural = require('natural');

<b>const router = express.Router();

router.post('/s-analyzer', function(req, res, next) {
  const { review } = req.body;
});</b>
Enter fullscreen mode Exit fullscreen mode

请注意,我们已经解构了用户的评论,因为我们期望从我们的request.body对象中获取它。

数据预处理

我们从用户那里获取的原始数据通常充斥着大量噪声,并且可能包含许多错误,因此需要将其转换为我们的NLP算法可理解/可用的格式。此步骤称为数据预处理。

将缩写转换为标准词汇

为了保持文本数据结构的统一,我们需要将缩写词(例如,I'm、you're等)转换为其标准词典(例如,I am、you are等)。为此,我们在终端上运行以下命令来安装软件包apos-to-lex-form :

npm install --save apos-to-lex-form
Enter fullscreen mode Exit fullscreen mode

接下来,我们将其导入到我们的/routes/nlp.js文件中并将其用于数据转换:

const express = require('express');
<b>const aposToLexForm = require('apos-to-lex-form');</b>
const natural = require('natural');

const router = express.Router();

router.post('/s-analyzer', function(req, res, next) {
  const { review } = req.body;
  <b>const lexedReview = aposToLexForm(review);</b>
});
Enter fullscreen mode Exit fullscreen mode

将文本数据转换为小写

在情绪分析过程中,我们希望所有数据都采用统一的格式。此步骤可确保我们的算法将“good”和“GOOD”视为相同的单词。我们将使用 JavaScript 的默认toLowerCase()函数来实现这一点:

...

const router = express.Router();

router.post('/s-analyzer', function(req, res, next) {
  const { review } = req.body;
  const lexedReview = aposToLexForm(review);
  <b>const casedReview = lexedReview.toLowerCase();</b>
});
Enter fullscreen mode Exit fullscreen mode

删除非字母字符和特殊字符

为了提高对用户情绪进行分类的准确性,我们将删除特殊字符和数字标记,因为它们对情绪没有贡献。此过程将确保我们的文本数据仅包含字母字符。

让我们使用 JavaScript 的默认replace()函数来实现这一点:

...

const router = express.Router();

router.post('/s-analyzer', function(req, res, next) {
  const { review } = req.body;
  const lexedReview = aposToLexForm(review);
  const casedReview = lexedReview.toLowerCase();
  <b>const alphaOnlyReview = casedReview.replace(/[^a-zA-Z\s]+/g, '');</b>
});
Enter fullscreen mode Exit fullscreen mode

标记化

这是将文本拆分成各个有意义的单元的过程。我们可以将单词视为句子的标记,将句子视为段落的标记。

下一步,我们将使用WordTokenizer导入的 Natural 包:

...

const router = express.Router();

router.post('/s-analyzer', function(req, res, next) {
  const { review } = req.body;
  const lexedReview = aposToLexForm(review);
  const casedReview = lexedReview.toLowerCase();
  const alphaOnlyReview = casedReview.replace(/[^a-zA-Z\s]+/g, '');

  <b>const { WordTokenizer } = natural;
  const tokenizer = new WordTokenizer();
  const tokenizedReview = tokenizer.tokenize(alphaOnlyReview);</b>
});
Enter fullscreen mode Exit fullscreen mode

纠正拼写错误的单词

由于产品评论是由用户手动撰写的,因此出现拼写错误的可能性很高。在将数据传递给情绪分析算法之前,让我们使用spelling-corrector包来纠正拼写错误的单词。这样,如果用户错误地输入了lov,正确的拼写love就会传递给我们的算法。

让我们首先使用以下命令进行安装:

npm install --save spelling-corrector
Enter fullscreen mode Exit fullscreen mode

接下来,我们将以下突出显示的行添加到我们的./routes/nlp.js文件中:

...
<b>const SpellCorrector = require('spelling-corrector');</b>

const router = express.Router();

<b>const spellCorrector = new SpellCorrector();
spellCorrector.loadDictionary();</b>

router.post('/s-analyzer', function(req, res, next) {
  const { review } = req.body;
  const lexedReview = aposToLexForm(review);
  const casedReview = lexedReview.toLowerCase();
  const alphaOnlyReview = casedReview.replace(/[^a-zA-Z\s]+/g, '');

  const { WordTokenizer } = natural;
  const tokenizer = new WordTokenizer();
  const tokenizedReview = tokenizer.tokenize(alphaOnlyReview);

  <b>tokenizedReview.forEach((word, index) => {
    tokenizedReview[index] = spellCorrector.correct(word);
  })</b>
});
Enter fullscreen mode Exit fullscreen mode

删除停用词

停用词通常是语言中最常用的词,在处理之前会被过滤掉。例如, butaorwhat就是停用词。由于这些词对用户的情绪没有影响,因此删除它们将有助于我们专注于重要的关键词。

为此,我们将使用stopword包。让我们通过在终端上运行以下命令来安装它:

npm install --save stopword
Enter fullscreen mode Exit fullscreen mode

接下来,我们将以下突出显示的行添加到我们的./routes/nlp.js文件中:

...
<b>const SW = require('stopword');</b>

const router = express.Router();

<b>const spellCorrector = new SpellCorrector();
spellCorrector.loadDictionary();</b>

router.post('/s-analyzer', function(req, res, next) {
  const { review } = req.body;
  const lexedReview = aposToLexForm(review);
  const casedReview = lexedReview.toLowerCase();
  const alphaOnlyReview = casedReview.replace(/[^a-zA-Z\s]+/g, '');

  const { WordTokenizer } = natural;
  const tokenizer = new WordTokenizer();
  const tokenizedReview = tokenizer.tokenize(alphaOnlyReview);

  tokenizedReview.forEach((word, index) => {
    tokenizedReview[index] = spellCorrector.correct(word);
  })
  <b>const filteredReview = SW.removeStopwords(tokenizedReview);</b>
});
Enter fullscreen mode Exit fullscreen mode

词干提取

这是自然语言处理 (NLP) 中的一个词语规范化过程,用于将派生词或词形变化词转换为其原形或词根。例如,词干提取算法预计会将“giving”、“gave”和“giver”等词简化为它们的词根“give”。

对于我们的应用程序,我们不会单独执行此过程,因为SentimentAnalyzerNatural 库提供了在调用时提供词干提取器作为参数的选项。在分析过程中,单个单词将被转换为其词根形式。

使用 Natural 库进行情感分析

现在我们已经有了所需状态的文本数据,我们可以使用SentimentAnalyzerNatural 来分析用户的评论。

Natural 库中的情绪分析算法基于一个为单词分配极性的词汇表。例如,“好”这个词的极性为3,而“坏”的极性为-3。该算法通过对一段文本中每个单词的极性求和,并用句子长度进行归一化来进行情绪计算。

这就是为什么预处理和去除数据中的所有噪音是获得更准确结果的必要步骤。如果我们的算法返回负值,则文本的情绪被认为是负面的;如果返回正值,则文本的情绪被认为是正面的;如果返回……,则文本的情绪被认为是中性的0

构造SentimentAnalyzer函数有三个参数:

  • 文本数据的语言
  • 词干提取器
  • 词汇表(目前支持 AFINN、Senticon 和 Pattern)

这是来自 Natural 库的官方情感分析文档的链接。

为了在我们的应用程序中使用该算法,我们将以下突出显示的代码添加到我们的./routes/nlp.js文件中:

...

router.post('/s-analyzer', function(req, res, next) {
  const { review } = req.body;
  const lexedReview = aposToLexForm(review);
  const casedReview = lexedReview.toLowerCase();
  const alphaOnlyReview = casedReview.replace(/[^a-zA-Z\s]+/g, '');

  const { WordTokenizer } = natural;
  const tokenizer = new WordTokenizer();
  const tokenizedReview = tokenizer.tokenize(alphaOnlyReview);

  tokenizedReview.forEach((word, index) => {
    tokenizedReview[index] = spellCorrector.correct(word);
  })
  const filteredReview = SW.removeStopwords(tokenizedReview);

  <b>const { SentimentAnalyzer, PorterStemmer } = natural;
  const analyzer = new SentimentAnalyzer('English', PorterStemmer, 'afinn');
  const analysis = analyzer.getSentiment(filteredReview);

  res.status(200).json({ analysis });</b>
});

<b>module.exports = router;</b>
Enter fullscreen mode Exit fullscreen mode

在我们新添加的行中,我们解构了Natural 库中的SentimentAnalyzer和方法,然后创建了一个新变量,并将我们的情感分析结果分配给它。PorterStemmeranalyzer

请注意,在SentimentAnalyzer构造函数中,我们提供了参数English(因为这是我们期望用户使用的语言)、PorterStemmer(我们为分析选择的词干分析器类型)和afinn(我们用于分析的词汇类型)。

将我们的 NLP 路由连接到我们的服务器

设置好路由后sentiment analysis,下一步就是将其连接到 Express 服务器。为此,我们将导入nlp router./app.js文件中,并将其添加为带有路径的路由/api/nlp

我们将以下突出显示的行添加到我们的./app.js文件中:

var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
<b>var nlpRouter = require('./routes/nlp');</b>

var app = express();

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
<b>app.use('/api/nlp', nlpRouter);</b>

module.exports = app;
Enter fullscreen mode Exit fullscreen mode

使用我们的前端

现在我们已经设置好了路由,接下来将其连接到应用程序的前端。我们将添加一个简单的表单来收集用户的评论,以及一个用于进行 API 调用的 JavaScript 函数。

让我们修改一下,./public/index.html file使其看起来像这样:

<html>

<head>
  <title>Sentiment Analyzer</title>
  <link rel="stylesheet" href="/stylesheets/style.css">
</head>

<body>
  <h1 id="title">Please write a review for this product:</h1>
  <form id="reviewForm">
    <textarea id="review" rows="4" cols="50"></textarea>
  </form>

  <div id="emojiSection"></div>

  <script type="text/javascript" src="./javascripts/index.js"></script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

接下来,在/public/javascripts文件夹中,让我们创建一个新文件index.js并将以下几行代码粘贴到其中:

const submitReview = (e) => {
  e.preventDefault();
  const review = document.getElementById('review').value;
  const options = {
    method: 'POST',
    body: JSON.stringify({ review }),
    headers: new Headers({ 'Content-Type': 'application/json' })
  }

  const emojiSection = document.getElementById('emojiSection');
  const title = document.getElementById('title');
  const outline = document.querySelector(':focus');

  fetch('/api/nlp/s-analyzer', options)
    .then(res => res.json())
    .then (({ analysis }) => {
      if (analysis < 0) {
        emojiSection.innerHTML = '<img src="https://img.icons8.com/emoji/96/000000/angry-face.png">';
        title.style.color = 'red';
        outline.style.borderColor = 'red';
      };
      if (analysis === 0) {
        emojiSection.innerHTML = '<img src="https://img.icons8.com/officel/80/000000/neutral-emoticon.png">';
        title.style.color = '#00367c';
        outline.style.borderColor = '#00367c';
      }
      if (analysis > 0) {
        emojiSection.innerHTML = '<img src="https://img.icons8.com/color/96/000000/happy.png">';
        title.style.color = 'green';
        outline.style.borderColor = 'green'
      }
    })
    .catch(err => {
      emojiSection.innerHTML = 'There was an error processing your request!'
    })
}

document.getElementById('review').addEventListener('keyup', submitReview);
document.getElementById('reviewForm').addEventListener('submit', submitReview);
Enter fullscreen mode Exit fullscreen mode

emojiSection div请注意,我们正在为我们在文件中创建的渲染一个表情符号index.html。我们还会根据从 API 收到的情绪值更改应用程序的颜色:小于 的结果0被视为负面,大于 的结果被视为0正面,等于 的结果被视为0中性。

现在,当我们启动应用程序并导航到时http://localhost:3000/,它应该能够根据我们的表单输入计算出我们产品评论的情绪分析,就像下面的演示一样:

情绪分析应用预览

结论

在本文中,我们介绍了使用 Node.js 进行自然语言处理的基础知识,并构建了一个情绪分析应用程序,该应用程序可以根据从用户评论中收到的文本数据计算用户的情绪。

以下是我们演示应用的 GitHub 仓库链接:node_nlp_sentiment_analysis 。如果您在使用 Node.js 进行 NLP 方面需要任何帮助,欢迎通过Twitter联系我。


仅 200 ‎✅:监控失败并显示生产中的 GraphQL 请求

虽然 GraphQL 有一些调试请求和响应的功能,但确保 GraphQL 可靠地向生产环境应用提供资源才是重中之重。如果您希望确保向后端或第三方服务发出的网络请求成功,不妨尝试 LogRocket。

替代文本

LogRocket就像 Web 应用的 DVR,可以记录您网站上发生的所有事件。您无需猜测问题发生的原因,而是可以汇总并报告有问题的 GraphQL 请求,从而快速了解根本原因。此外,您还可以跟踪 Apollo 客户端状态并检查 GraphQL 查询的键值对。

LogRocket 会为您的应用提供工具,记录基准性能时间,例如页面加载时间、首字节加载时间、慢速网络请求,以及 Redux、NgRx 和 Vuex 的操作/状态。立即免费开始监控。


使用 Node.js 构建情绪分析应用程序一文首先出现在LogRocket 博客上。

鏂囩珷鏉ユ簮锛�https://dev.to/bnevilleoneill/building-a-sentiment-analysis-app-with-node-js-23in
PREV
CSS 实用程序类:您的可扩展样式库有哪些潜在的缺点?
NEXT
Node.js v12 新增的强大功能