Add Sentiment Analysis lab

This commit is contained in:
2025-11-11 18:37:14 +01:00
parent dece3dba69
commit 18b1a03795
5 changed files with 167 additions and 1 deletions

View File

@@ -0,0 +1,33 @@
import org.springframework.boot.gradle.plugin.SpringBootPlugin
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
description = "Sentiment Analysis Lab"
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
}
dependencyManagement {
imports {
mavenBom SpringBootPlugin.BOM_COORDINATES
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.opencsv:opencsv:5.7.1'
implementation 'edu.stanford.nlp:stanford-corenlp:4.5.9:models'
implementation 'edu.stanford.nlp:stanford-corenlp:4.5.9'
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

View File

@@ -0,0 +1,120 @@
package com.example.senti;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.neural.rnn.RNNCoreAnnotations;
import edu.stanford.nlp.pipeline.*;
import edu.stanford.nlp.sentiment.SentimentCoreAnnotations;
import edu.stanford.nlp.util.CoreMap;
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;
import org.springframework.core.io.ClassPathResource;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class ProductReviewAnalyzer {
private StanfordCoreNLP pipeline;
public static void main(String[] args) {
ProductReviewAnalyzer analyzer = new ProductReviewAnalyzer();
analyzer.initialize();
try {
// Load reviews from CSV
List<String[]> reviews = analyzer.loadReviews("/product_reviews.csv");
Map<String, Integer> sentimentDistribution = new LinkedHashMap<>();
sentimentDistribution.put("Very Positive", 0);
sentimentDistribution.put("Positive", 0);
sentimentDistribution.put("Neutral", 0);
sentimentDistribution.put("Negative", 0);
sentimentDistribution.put("Very Negative", 0);
System.out.println("=== Review Sentiment Analysis ===");
for (String[] review : reviews) {
if (review[0].equals("review_id")) continue; // Skip header
String sentiment = analyzer.analyzeSentiment(review[1]);
sentimentDistribution.put(sentiment, sentimentDistribution.get(sentiment) + 1);
System.out.printf("Review %2s: %-60s - %s\n",
review[0],
shortenText(review[1], 55),
sentiment);
}
// Generate report
analyzer.generateReport(sentimentDistribution, reviews.size() - 1);
} catch (IOException | CsvException e) {
e.printStackTrace();
}
}
public void initialize() {
// Set up pipeline properties
Properties props = new Properties();
props.setProperty("annotators", "tokenize, ssplit, parse, sentiment");
props.setProperty("coref.algorithm", "neural");
this.pipeline = new StanfordCoreNLP(props);
}
public List<String[]> loadReviews(String filePath) throws IOException, CsvException {
try (CSVReader reader = new CSVReader(new InputStreamReader(new ClassPathResource(filePath).getInputStream()))) {
return reader.readAll();
}
}
public String analyzeSentiment(String text) {
int mainSentiment = 0;
int longest = 0;
Annotation annotation = pipeline.process(text);
for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) {
int sentiment = RNNCoreAnnotations.getPredictedClass(sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class));
String partText = sentence.toString();
if (partText.length() > longest) {
mainSentiment = sentiment;
longest = partText.length();
}
}
// Convert numeric sentiment to text
return switch (mainSentiment) {
case 0 -> "Very Negative";
case 1 -> "Negative";
case 2 -> "Neutral";
case 3 -> "Positive";
case 4 -> "Very Positive";
default -> "Neutral";
};
}
public void generateReport(Map<String, Integer> sentimentCounts, int totalReviews) {
System.out.println("\n=== Sentiment Analysis Report ===");
System.out.printf("Total Reviews Analyzed: %d\n\n", totalReviews);
System.out.println("Sentiment Distribution:");
for (Map.Entry<String, Integer> entry : sentimentCounts.entrySet()) {
double percentage = (entry.getValue() * 100.0) / totalReviews;
System.out.printf("%-12s: %2d reviews (%5.1f%%) %s\n",
entry.getKey(),
entry.getValue(),
percentage,
generateBar(percentage));
}
}
private static String generateBar(double percentage) {
int bars = (int) (percentage / 5);
return "[" + new String(new char[bars]).replace("\0", "=") + "]";
}
private static String shortenText(String text, int maxLength) {
return text.length() > maxLength ? text.substring(0, maxLength - 3) + "..." : text;
}
}

View File

@@ -0,0 +1 @@
spring.application.name=senti

View File

@@ -0,0 +1,11 @@
review_id,review_text
1,"This product is absolutely amazing! Works perfectly."
2,"Terrible quality. Broke after 2 days of use."
3,"Good value for the price. Very satisfied."
4,"Not what I expected. Poor packaging."
5,"Excellent customer service and fast shipping."
6,"The item arrived damaged. Very disappointed."
7,"Works well but instructions could be better."
8,"Best purchase I've made this year!"
9,"Overpriced for what you get."
10,"Highly recommend this to all my friends."
1 review_id review_text
2 1 This product is absolutely amazing! Works perfectly.
3 2 Terrible quality. Broke after 2 days of use.
4 3 Good value for the price. Very satisfied.
5 4 Not what I expected. Poor packaging.
6 5 Excellent customer service and fast shipping.
7 6 The item arrived damaged. Very disappointed.
8 7 Works well but instructions could be better.
9 8 Best purchase I've made this year!
10 9 Overpriced for what you get.
11 10 Highly recommend this to all my friends.

View File

@@ -7,4 +7,5 @@ include 'RetailManagementSystem:front-end'
include 'InventoryManagementSystem' include 'InventoryManagementSystem'
include 'SmartClinicManagementSystem:app' include 'SmartClinicManagementSystem:app'
include 'SoftwareDevChatbot' include 'SoftwareDevChatbot'
include 'RegressionPredictionLab' include 'RegressionPredictionLab'
include 'SentimentAnalysisLab'