El análisis de sentimientos es una técnica de procesamiento del lenguaje natural que se utiliza para determinar las emociones a partir de datos textuales. A menudo se realiza para conocer los requisitos del cliente, estudiar la opinión del producto en los comentarios de los usuarios, la toma de decisiones y más.
Tipos de análisis de sentimiento:
- Análisis de sentimiento de grano fino: se realiza cuando queremos precisión de polaridad en nuestros resultados. En este tipo de análisis, dividimos nuestros resultados en categorías de polaridad como muy negativo, negativo, positivo, muy positivo, neutral.
- Análisis de sentimientos basado en emociones: este tipo de análisis detecta diferentes tipos de emociones como felicidad, ira y tristeza.
- Análisis de sentimiento basado en aspectos: si queremos conocer aspectos o características particulares que los usuarios mencionan de manera positiva o negativa, entonces se utiliza este tipo de análisis. Por ejemplo, la revisión del usuario dice que la computadora portátil es muy buena, pero la batería es muy mala, por lo que aquí nuestro algoritmo basado en aspectos podría determinar que hay una opinión negativa sobre la batería, no sobre todo el producto.
Enfoque: en este artículo, crearemos una aplicación de análisis de sentimientos utilizando el Node js que analiza los datos de texto de los comentarios de los usuarios y utilizaremos una combinación de enfoque de análisis de sentimientos detallado y basado en emociones para derivar el sentimiento del usuario. Usaremos AFINN (léxico de palabras en inglés clasificadas por valencia con un número entero entre menos cinco (negativo) y más cinco (positivo)) que se incluye en la biblioteca natural que incluiremos como un paquete npm en nuestra aplicación.
A continuación se muestra la implementación paso a paso:
Instalación de Node JS: Siga el enlace para descargar e instalar Node.js: Descargar Node.js. Nos aseguraremos de tener el Node instalado en nuestro sistema ejecutando el siguiente comando:
node -v
Paso 1: Cree una carpeta separada y, con la ayuda de un terminal o símbolo del sistema, navegue hasta esta carpeta y muévase a esa carpeta.
cd <your folder location>
Paso 2: Cree package.json escribiendo el siguiente comando en la terminal:
npm init -y
Para saber más sobre package.json, haga clic aquí .
Paso 3: Instale las siguientes dependencias.
- Express: Express es un marco de aplicación web Node.js mínimo y flexible que proporciona un conjunto sólido de funciones para aplicaciones web y móviles.
- Natural: un paquete de Node.js que admite la mayoría de los algoritmos NLP
- Palabra vacía: palabra vacía, paquete de Node.js que le permite quitar palabras vacías de un texto de entrada
npm install --save express natural stopword
Estructura del proyecto: La estructura del proyecto se verá así:
Paso 4: Primero, crearemos un servidor HTTP básico.
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..."); });
Paso 5: Cree una nueva ruta y asígnele la ruta /retroalimentación, cuando los usuarios envíen una solicitud POST a nuestra ruta con la retroalimentación en el cuerpo de su solicitud, deberían recibir una respuesta que contenga su análisis de opinión.
server.js
// Include Routes app.post("/feedback",(request,response)=>{ const { feedback } = request.body; });
Paso 6: Los datos que obtenemos de nuestros usuarios están llenos de muchos errores y ruido que tenemos que filtrar durante nuestro análisis. Para extraer información o sentimientos significativos, tenemos que filtrar los datos textuales de nuestros usuarios, este proceso se denomina filtración de datos.
Pasos para la filtración:
- Para mantener la estructura de nuestros datos, convertiremos todas las palabras a su forma estándar. Por ejemplo, Eres -> Eres.
- Todos nuestros datos textuales estarán en minúsculas ya que queremos que nuestro algoritmo de análisis trate brillante y BRILLANTE como la misma palabra.
- Eliminación de caracteres especiales y tokens numéricos ya que son solo elementos ruidosos, además su contribución en nuestros resultados será nula.
- La tokenización es uno de los pasos cruciales en este proceso de filtración, ya que es el proceso de dividir un texto en unidades significativas. Usaremos el WordTokenizer de nuestro paquete Natural importado.
- Eliminación de palabras vacías ya que estas palabras no contribuyen en nada al sentimiento del usuario, algunos ejemplos de palabras vacías incluyen: pero, a, o, etc.
- Proceso de normalización de palabras en PNL en el que se espera que el algoritmo de derivación reduzca las palabras a su palabra raíz. Por ejemplo “entrenando”, “entrenado” a “entrenar”. Sentiment Analyzer de la biblioteca Natural nos brinda la opción de proporcionar un lematizador como parámetro mientras lo llamamos. Durante su análisis, las palabras individuales se convertirán a su forma raíz.
Análisis de sentimiento usando Natural: El algoritmo de análisis de sentimiento de la biblioteca Natural usa AFINN , que es un léxico de palabras en inglés clasificadas por valencia con un número entero entre menos cinco (negativo) y más cinco (positivo). Calculando la suma de la polaridad de cada palabra en un fragmento de texto y normalizándola con la longitud de una oración, es como funciona el algoritmo. Si el algoritmo devuelve un valor negativo, eso significa que el sentimiento es negativo, si devuelve un valor positivo, eso significa que el sentimiento es positivo. El valor cero indica un sentimiento neutral.
Crearemos una ruta/retroalimentación en la que recopilaremos la retroalimentación de nuestros usuarios e implementaremos nuestro análisis. La función llamada convertToStandard convertirá todos nuestros datos a su forma estándar. La función convertTolowerCase convierte todos nuestros datos a minúsculas. La función removeNonAlpha eliminará las letras que no sean alfabéticas. A continuación, tokenizaremos nuestros datos y eliminaremos palabras vacías utilizando el paquete npm de palabras vacías. Después de todo este código de filtración de datos, usaremos un paquete natural, SentimentAnalyzer de Natural creará una puntuación de sentimiento a partir de la revisión de nuestro usuario. Por último, enviaremos esta puntuación de sentimiento basada en nuestro análisis como respuesta a nuestros usuarios.
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...'); });
Paso 7: para conectar la interfaz con nuestro servidor, debemos agregar una sola línea de código que se agregará en nuestro archivo server.js, lo que significa que todos nuestros archivos HTML, CSS y JS estáticos se servirán en / ruta.
servidor.js
app.use("/",express.static(__dirname + "/public"));
Ahora, crearemos un archivo HTML llamado index.html que será nuestra interfaz.
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Font CDN --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href= "https://fonts.googleapis.com/css2?family=Open+Sans&family=Outfit&family=M+PLUS+1+Code&display=swap" rel="stylesheet"> <title>Event Feedback Application</title> </head> <style> *{ margin: 0; padding: 0; } .feedback{ transition: all .3s; background-size: cover; min-height: 100vh; } .feedback.active{ filter: blur(8px); } .container{ display: flex; justify-content: center; flex-direction: column; align-items: center; } .container .form{ margin-top: 10%; background: #f1f5f3; padding: 1em 2.5em 1.7em 2.5em; display: flex; justify-content: center; align-items: center; flex-direction: column; } .form > div{ font-family: 'Open Sans',sans-serif; margin-top: 8%; } textarea{ font-family: 'Open Sans',sans-serif; padding: .8em; border: none; outline: none; resize: none; } button{ padding: .7em; cursor: pointer; outline: none; font-family: 'Open Sans',sans-serif; background: #000; border: 1px solid #222; color: #f1f5f3; } .results{ position: absolute; top: 40%; left: 50%; transform: translate(-50%,-50%); z-index: 999999; transition: all .5s; opacity: 0; pointer-events: none; } .results.active{ opacity: 1; pointer-events: visible; } .results .result-box{ background: #f1f5f3; padding: 2em 4em; } .result-box > div{ display: flex; justify-content: center; margin-top: 15%; } .sentiment p{ font-family:'M PLUS 1 Code',sans-serif; } .close-button button{ width: 100%; margin-top: 20%; background: rgb(255, 63, 102); } </style> <body> <!-- Toast Box --> <div class="results"> <div class="result-box"> <div class="emoji"> </div> <div class="sentiment"> </div> <div class="close-button"> <button class="close">❌</button> </div> </div> </div> <section class="feedback"> <div class="container"> <div class="form"> <div class="title"> <h2>Event Feedback ????</h2> </div> <div> <textarea cols="20" rows="5" id="feedbacktext" placeholder="Write..."> </textarea> </div> <div> <button id="submit">Submit</button> </div> </div> </div> </section> </body> <script src="main.js"></script> </html>
Paso 8: ahora en la carpeta /public, creemos un archivo llamado main.js, en el que agregaremos algunas funciones para realizar nuestra llamada a la API. Coge todos los elementos HTML. Entonces, nuestra lógica es que cuando nuestro usuario complete el formulario de comentarios, después de hacer clic en enviar, se debe llamar a una función y se debe realizar una llamada API a nuestro servidor node js. Agregaremos un evento de clic en nuestro botón, al hacer clic, haremos una llamada API a nuestro servidor y obtendremos una respuesta de acuerdo con nuestros comentarios. Según nuestra puntuación de sentimiento, mostraremos nuestros resultados con emojis.
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 = "<p>😄</p>"; sentiment.innerHTML = "<p>➕ Positive</p>"; }else if(score === 0){ emoji.innerHTML = "<p>😐</p>"; sentiment.innerHTML = "<p>Neutral</p>"; }else{ emoji.innerHTML = "<p>😡</p>"; sentiment.innerHTML = "<p>➖ Negative</p>"; } // 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"); })
Paso para ejecutar la aplicación: Para iniciar esta aplicación, ejecute el siguiente comando en el símbolo del sistema:
node server.js
Salida: navegue a http://localhost:5500/
Registros del servidor: