xbe.at

NLP and transformers / NLP core

Aspect-Based Sentiment Analysis with Python

9 min read, 16 sections

Contents
  1. Introduction to Aspect-Based Sentiment Analysis
  2. Implicit Sentiment in Aspect Terms
  3. Feature Extraction for Aspect Terms
  4. Dependency Parsing for Implicit Sentiment
  5. Word Embeddings for Context Understanding
  6. Aspect-Opinion Pair Extraction
  7. Contextual Sentiment Analysis
  8. Handling Negations and Intensifiers
  9. Aspect-Based Sentiment Summarization
  10. Aspect-Based Sentiment Classification
  11. Aspect Term Extraction using Topic Modeling
  12. Handling Sarcasm and Irony
  13. Real-life Example: Restaurant Review Analysis
  14. Real-life Example: Social Media Sentiment Analysis
  15. Challenges and Future Directions in Aspect-Based Implicit Sentiment Analysis
  16. Additional Resources

Introduction to Aspect-Based Sentiment Analysis

Aspect-based sentiment analysis is a natural language processing technique that aims to identify and extract opinions or sentiments associated with specific aspects of a product, service, or topic. Unlike general sentiment analysis, which provides an overall sentiment score, aspect-based sentiment analysis offers a more granular understanding of opinions.

import nltk
from nltk.sentiment import SentimentIntensityAnalyzer

text = "The phone's camera is excellent, but the battery life is disappointing."
sia = SentimentIntensityAnalyzer()
aspects = ['camera', 'battery']

for aspect in aspects:
    if aspect in text:
        sentence = next(sent for sent in nltk.sent_tokenize(text) if aspect in sent)
        sentiment = sia.polarity_scores(sentence)['compound']
        print(f"Sentiment for {aspect}: {sentiment}")

Implicit Sentiment in Aspect Terms

Implicit sentiment refers to opinions that are not directly expressed but can be inferred from the context. In aspect-based sentiment analysis, implicit sentiment poses a challenge as it requires understanding nuances and context beyond explicit statements.

def detect_implicit_sentiment(text, aspect):
    positive_indicators = ["great", "awesome", "excellent"]
    negative_indicators = ["poor", "disappointing", "frustrating"]
    
    words = text.lower().split()
    aspect_index = words.index(aspect.lower())
    context = words[max(0, aspect_index - 3):aspect_index + 4]
    
    for word in context:
        if word in positive_indicators:
            return "Positive"
        elif word in negative_indicators:
            return "Negative"
    return "Neutral"

text = "The camera quality surprised me. I didn't expect such results."
print(detect_implicit_sentiment(text, "camera"))

Feature Extraction for Aspect Terms

To identify aspect terms and their associated sentiments, we need to extract relevant features from the text. This process involves techniques such as part-of-speech tagging, dependency parsing, and named entity recognition.

import spacy

nlp = spacy.load("en_core_web_sm")

def extract_aspect_features(text):
    doc = nlp(text)
    aspects = []
    for token in doc:
        if token.dep_ in ["nsubj", "dobj", "attr", "nmod"] and token.pos_ == "NOUN":
            aspects.append(token.text)
    return aspects

text = "The restaurant's ambiance was cozy, and the food was delicious."
print(extract_aspect_features(text))

Dependency Parsing for Implicit Sentiment

Dependency parsing can help identify relationships between words in a sentence, which is crucial for understanding implicit sentiment. By analyzing the syntactic structure, we can infer sentiment even when it's not explicitly stated.

import spacy

nlp = spacy.load("en_core_web_sm")

def analyze_implicit_sentiment(text, aspect):
    doc = nlp(text)
    for token in doc:
        if token.text.lower() == aspect.lower():
            for child in token.children:
                if child.pos_ == "ADJ":
                    return child.text
    return "No implicit sentiment found"

text = "The phone's camera captures stunning details."
print(analyze_implicit_sentiment(text, "camera"))

Word Embeddings for Context Understanding

Word embeddings can help capture semantic relationships between words, which is essential for understanding implicit sentiment. By representing words as dense vectors, we can identify similar concepts and context-dependent meanings.

from gensim.models import Word2Vec
import nltk

sentences = [
    "The camera quality is amazing",
    "The battery life is disappointing",
    "The screen resolution is impressive"
]

tokenized_sentences = [nltk.word_tokenize(sentence.lower()) for sentence in sentences]
model = Word2Vec(sentences=tokenized_sentences, vector_size=100, window=5, min_count=1, workers=4)

print(model.wv.most_similar("camera"))

Aspect-Opinion Pair Extraction

Identifying aspect-opinion pairs is crucial for accurate sentiment analysis. This process involves finding the relationship between aspect terms and their corresponding sentiment expressions.

import spacy

nlp = spacy.load("en_core_web_sm")

def extract_aspect_opinion_pairs(text):
    doc = nlp(text)
    pairs = []
    for token in doc:
        if token.dep_ in ["nsubj", "dobj"] and token.pos_ == "NOUN":
            for child in token.children:
                if child.pos_ == "ADJ":
                    pairs.append((token.text, child.text))
    return pairs

text = "The phone has a bright screen and a powerful processor."
print(extract_aspect_opinion_pairs(text))

Contextual Sentiment Analysis

Context plays a crucial role in understanding implicit sentiment. By considering surrounding words and phrases, we can better interpret the sentiment associated with aspect terms.

import nltk
from nltk.sentiment import SentimentIntensityAnalyzer

def analyze_contextual_sentiment(text, aspect, window_size=5):
    words = nltk.word_tokenize(text)
    aspect_index = words.index(aspect)
    start = max(0, aspect_index - window_size)
    end = min(len(words), aspect_index + window_size + 1)
    context = " ".join(words[start:end])
    
    sia = SentimentIntensityAnalyzer()
    sentiment = sia.polarity_scores(context)['compound']
    return sentiment

text = "Despite its small size, the camera produces excellent quality photos."
print(analyze_contextual_sentiment(text, "camera"))

Handling Negations and Intensifiers

Negations and intensifiers can significantly affect sentiment polarity. Identifying and properly handling these linguistic elements is crucial for accurate implicit sentiment analysis.

import nltk
from nltk.sentiment import SentimentIntensityAnalyzer

def handle_negations_intensifiers(text):
    words = nltk.word_tokenize(text)
    negations = {"not", "no", "never", "neither", "hardly", "scarcely"}
    intensifiers = {"very", "extremely", "incredibly", "absolutely"}
    
    modified_text = []
    negate = False
    intensify = False
    
    for word in words:
        if word.lower() in negations:
            negate = True
        elif word.lower() in intensifiers:
            intensify = True
        else:
            if negate:
                word = "NOT_" + word
                negate = False
            if intensify:
                word = "INTENSIFIED_" + word
                intensify = False
        modified_text.append(word)
    
    return " ".join(modified_text)

text = "The camera is not very good, but the screen is extremely bright."
modified_text = handle_negations_intensifiers(text)
print(modified_text)

sia = SentimentIntensityAnalyzer()
print(sia.polarity_scores(modified_text))

Aspect-Based Sentiment Summarization

Summarizing sentiment for multiple aspects provides a comprehensive overview of opinions. This technique is particularly useful for product reviews or customer feedback analysis.

import nltk
from nltk.sentiment import SentimentIntensityAnalyzer

def summarize_aspect_sentiments(reviews, aspects):
    sia = SentimentIntensityAnalyzer()
    summary = {aspect: [] for aspect in aspects}
    
    for review in reviews:
        sentences = nltk.sent_tokenize(review)
        for sentence in sentences:
            for aspect in aspects:
                if aspect in sentence.lower():
                    sentiment = sia.polarity_scores(sentence)['compound']
                    summary[aspect].append(sentiment)
    
    for aspect, sentiments in summary.items():
        if sentiments:
            avg_sentiment = sum(sentiments) / len(sentiments)
            print(f"{aspect}: {avg_sentiment:.2f}")
        else:
            print(f"{aspect}: No mentions")

reviews = [
    "The camera quality is impressive, but the battery life is disappointing.",
    "I love the sleek design, and the screen resolution is amazing.",
    "The processor is fast, but the camera could be better."
]
aspects = ["camera", "battery", "design", "screen", "processor"]
summarize_aspect_sentiments(reviews, aspects)

Aspect-Based Sentiment Classification

Classifying sentiment for specific aspects involves training a model to recognize patterns and features associated with different sentiment polarities for each aspect.

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report

def train_aspect_sentiment_classifier(data, aspects):
    classifiers = {}
    for aspect in aspects:
        X = [text for text, asp, _ in data if asp == aspect]
        y = [sentiment for _, asp, sentiment in data if asp == aspect]
        
        vectorizer = TfidfVectorizer()
        X_vectorized = vectorizer.fit_transform(X)
        
        X_train, X_test, y_train, y_test = train_test_split(X_vectorized, y, test_size=0.2, random_state=42)
        
        classifier = SVC()
        classifier.fit(X_train, y_train)
        
        y_pred = classifier.predict(X_test)
        print(f"Classification Report for {aspect}:")
        print(classification_report(y_test, y_pred))
        
        classifiers[aspect] = (vectorizer, classifier)
    
    return classifiers

# Example data: (text, aspect, sentiment)
data = [
    ("The camera takes amazing photos", "camera", "positive"),
    ("Battery life is disappointing", "battery", "negative"),
    ("The screen is bright and clear", "screen", "positive"),
    ("Camera quality could be better", "camera", "negative"),
    ("I'm impressed with the long-lasting battery", "battery", "positive")
]

aspects = ["camera", "battery", "screen"]
classifiers = train_aspect_sentiment_classifier(data, aspects)

Aspect Term Extraction using Topic Modeling

Topic modeling techniques like Latent Dirichlet Allocation (LDA) can be used to automatically extract aspect terms from a corpus of documents. This approach is particularly useful when dealing with large datasets and unknown aspects.

from gensim import corpora
from gensim.models import LdaModel
import nltk
from nltk.corpus import stopwords

def extract_aspects_lda(documents, num_topics=5, num_words=5):
    stop_words = set(stopwords.words('english'))
    texts = [[word for word in nltk.word_tokenize(doc.lower()) if word.isalnum() and word not in stop_words]
             for doc in documents]
    
    dictionary = corpora.Dictionary(texts)
    corpus = [dictionary.doc2bow(text) for text in texts]
    
    lda_model = LdaModel(corpus=corpus, id2word=dictionary, num_topics=num_topics)
    
    topics = lda_model.print_topics(num_words=num_words)
    for topic in topics:
        print(topic)

documents = [
    "The camera on this phone is amazing. Great picture quality.",
    "Battery life could be better. It drains quickly.",
    "The screen is bright and crisp. Colors look fantastic.",
    "Processing speed is impressive. Apps load quickly.",
    "The design is sleek and modern. Feels great in hand."
]

extract_aspects_lda(documents)

Handling Sarcasm and Irony

Sarcasm and irony pose significant challenges in sentiment analysis, especially for implicit sentiment. Detecting these linguistic devices requires advanced natural language understanding and context analysis.

import nltk
from nltk.sentiment import SentimentIntensityAnalyzer

def detect_sarcasm(text):
    sia = SentimentIntensityAnalyzer()
    sentences = nltk.sent_tokenize(text)
    
    conflicting_sentiments = False
    overall_sentiment = sia.polarity_scores(text)['compound']
    
    for sentence in sentences:
        sentence_sentiment = sia.polarity_scores(sentence)['compound']
        if (overall_sentiment > 0 and sentence_sentiment < -0.5) or \
           (overall_sentiment < 0 and sentence_sentiment > 0.5):
            conflicting_sentiments = True
            break
    
    if conflicting_sentiments:
        return "Potential sarcasm detected"
    else:
        return "No sarcasm detected"

text1 = "The weather is just perfect today. I love getting soaked in the rain."
text2 = "The new feature is so useful. It only crashed my computer twice today."

print(detect_sarcasm(text1))
print(detect_sarcasm(text2))

Real-life Example: Restaurant Review Analysis

Let's apply aspect-based implicit sentiment analysis to a real-life scenario: analyzing restaurant reviews. This example demonstrates how to extract aspects, identify sentiments, and provide a comprehensive analysis of customer feedback.

import nltk
from nltk.sentiment import SentimentIntensityAnalyzer
import spacy

nlp = spacy.load("en_core_web_sm")
sia = SentimentIntensityAnalyzer()

def analyze_restaurant_review(review):
    aspects = {
        "food": ["dish", "taste", "flavor", "menu"],
        "service": ["waiter", "staff", "service"],
        "ambiance": ["atmosphere", "decor", "music"],
        "price": ["cost", "value", "expensive", "cheap"]
    }
    
    doc = nlp(review)
    results = {}
    
    for sentence in doc.sents:
        for aspect, keywords in aspects.items():
            if any(keyword in sentence.text.lower() for keyword in keywords):
                sentiment = sia.polarity_scores(sentence.text)['compound']
                if aspect not in results:
                    results[aspect] = []
                results[aspect].append(sentiment)
    
    for aspect, sentiments in results.items():
        avg_sentiment = sum(sentiments) / len(sentiments)
        print(f"{aspect.capitalize()}: {avg_sentiment:.2f}")

review = """
The new Italian restaurant downtown is a hidden gem. The pasta dishes are bursting with flavor, 
and the homemade sauces are to die for. While the menu is a bit pricey, the quality justifies 
the cost. The staff was attentive, but the service was slow during peak hours. The rustic decor 
and soft background music create a cozy atmosphere perfect for a romantic dinner.
"""

analyze_restaurant_review(review)

Real-life Example: Social Media Sentiment Analysis

Social media platforms are rich sources of opinions and sentiments. This example demonstrates how to perform aspect-based implicit sentiment analysis on Twitter data, focusing on a specific product or brand.

import re
from textblob import TextBlob

def clean_tweet(tweet):
    return ' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)", " ", tweet).split())

def get_tweet_sentiment(tweet):
    analysis = TextBlob(clean_tweet(tweet))
    if analysis.sentiment.polarity > 0:
        return 'positive'
    elif analysis.sentiment.polarity == 0:
        return 'neutral'
    else:
        return 'negative'

def analyze_product_tweets(tweets, aspects):
    results = {aspect: {'positive': 0, 'negative': 0, 'neutral': 0} for aspect in aspects}
    
    for tweet in tweets:
        clean_text = clean_tweet(tweet)
        for aspect in aspects:
            if aspect.lower() in clean_text.lower():
                sentiment = get_tweet_sentiment(clean_text)
                results[aspect][sentiment] += 1
    
    for aspect, sentiments in results.items():
        total = sum(sentiments.values())
        if total > 0:
            print(f"\nAspect: {aspect}")
            for sentiment, count in sentiments.items():
                percentage = (count / total) * 100
                print(f"{sentiment.capitalize()}: {percentage:.2f}%")

tweets = [
    "The new smartphone camera is amazing! #TechReview",
    "Battery life on this phone is disappointing. Needs improvement.",
    "Love the sleek design, but the price is too high for what you get.",
    "Screen resolution is top-notch. Colors are vibrant and clear.",
    "The phone's processor is lightning fast. Apps load instantly!"
]

aspects = ["camera", "battery", "design", "price", "screen", "processor"]
analyze_product_tweets(tweets, aspects)

Challenges and Future Directions in Aspect-Based Implicit Sentiment Analysis

Aspect-based implicit sentiment analysis faces several challenges and has promising future directions:

  1. Context Understanding: Improving models to better understand context and nuances in language.
  2. Multimodal Analysis: Incorporating image and video data alongside text for more comprehensive sentiment analysis.
  3. Cross-lingual Sentiment Analysis: Developing models that can perform well across multiple languages.
  4. Handling Figurative Language: Enhancing detection and interpretation of sarcasm, irony, and metaphors.
  5. Real-time Analysis: Developing efficient algorithms for processing large volumes of data in real-time.

Future research may focus on deep learning approaches, transfer learning, and unsupervised methods to address these challenges and improve the accuracy and scalability of aspect-based implicit sentiment analysis.

Additional Resources

For those interested in diving deeper into aspect-based implicit sentiment analysis, here are some valuable resources:

  1. ArXiv paper: "Aspect-Based Sentiment Analysis: A Survey of Deep Learning Methods" by Li et al. (2019) URL: https://arxiv.org/abs/1908.04962
  2. ArXiv paper: "A Survey on Aspect-Based Sentiment Analysis: Tasks, Approaches and Applications" by Zhang et al. (2022) URL: https://arxiv.org/abs/2203.01054
  3. ArXiv paper: "Deep Learning for Aspect-Level Sentiment Classification: Survey, Vision, and Challenges" by Zhou et al. (2019) URL: https://arxiv.org/abs/1905.04655

These papers provide comprehensive overviews of recent advancements, methodologies, and challenges in the field of aspect-based sentiment analysis, including implicit sentiment detection.

More in NLP core

  1. Building Robust NLP Models with Data Augmentation8 min

    Data augmentation is a technique used to increase the diversity and size of training data by creating modified versions of existing data. In Natural Language...

  2. Comparing NLTK and spaCy for NLP in Python8 min

    Natural Language Processing (NLP) is a crucial field in artificial intelligence, and two popular Python libraries for NLP are NLTK and spaCy. This...

  3. Comparing Transformer Models for Sentiment Analysis13 min

    The Transformer architecture revolutionized NLP by introducing self-attention mechanisms that capture contextual relationships between words. This...

  4. Comprehensive Sentiment Analysis Techniques11 min

    Sentiment Analysis is a powerful Natural Language Processing technique used to determine the emotional tone behind text data. It helps businesses...

  5. Deep Speech 2 Python-Powered Speech Recognition10 min

    Deep Speech 2 is an advanced speech recognition system developed by Baidu Research. It builds upon the original Deep Speech model, offering improved accuracy...

  6. Document Understanding Transformer for Optical Character Recognition10 min

    Document Understanding Transformer is a powerful deep learning model designed to comprehend and extract information from various types of documents. It...