A challenge in sentiment analysis is understanding sarcasm and irony because they are sophisticated forms of speech where the authors write opposite of what they mean. Irony is often used to emphasize the opposite of what is written and Sarcasm is used to imply criticism (Hernández-Farías & Rosso, 2017).
Text could be classified as positive or negative. When reading data, we could have class imbalance if positive and negative sentiments aren’t equally distributed. It can be avoided by
- Oversampling - Take more data from the smaller dataset
- Undersampling - Remove important data from larger dataset
- Weighted loss - Tell the model data from smaller dataset is more important then the data from larger dataset (Alahmadi et al., 2025)
Learning from just positive and negative sentiments will not permit accurate classification of neutral data, so the use of neutral data in training examples gives better distinction between positive and negative data (Koppel & Schler, 2006). The problem with neutral data is it could either be
- Objective statements that express no sentiment at all
- Mix of both Positive and Negative statements
ML models that are used for sentiment analysis
- SVM and Naive Bayes are computationally efficient and interpretable but rely on manual feature engineering and struggle with linguistic nuances
- Rule based and Lexicon based approaches offer transperency and low resource requirement but are static which limits scalability and generalization
- Deep Learning models provide better accuracy by learning hierarchial and semantic representation directly from data but require large amount of labeled data, computational resources and their decision making is hard to interpret
- Pre-trained transformer models have enabled robust performance with minimal supervision but have high costs of pretraining and reduced interpretability (Alahmadi et al., 2025)
References
Alahmadi, K., Alharbi, S., Chen, J., & Wang, X. (2025). Generalizing sentiment analysis: A review of progress, challenges, and emerging directions. Social Network Analysis and Mining, 15, 45. https://link.springer.com/article/10.1007/s13278-025-01461-8
Hernández-Farías, I. D., & Rosso, P. (2017). Irony, sarcasm, and sentiment analysis. In Sentiment analysis in social networks. Elsevier. https://www.sciencedirect.com/science/chapter/edited-volume/abs/pii/B9780128044124000073
Koppel, M., & Schler, J. (2006). The importance of neutral examples for learning sentiment. Computational Intelligence, 22(2), 100–115. https://www.microsoft.com/en-us/research/publication/the-importance-of-neutral-examples-for-learning-sentiment/
# Rule based sentiment analysis with TextBlob
from textblob import sentiments
from textblob import TextBlob
texts=[
"The weather is terrible today.",
"I am so excited about the new movie release."
]
for text in texts:
blob=TextBlob(text)
sentiment=blob.sentiment
print(f"Text: {text}")
print(f"Polarity: {sentiment.polarity}, Subjectivity: {sentiment.subjectivity}")
print() # Custom Rule-Based Sentiment Analysis with Afinn
from afinn import Afinn
afinn=Afinn()
texts=[
"I hate waiting in long lines.",
"The food at the restaurant was fantastic."
]
for text in texts:
sentiment_score=afinn.score(text)
sentiment='Positive' if sentiment_score>0 else "Negative" if sentiment_score<0 else "Neutral"
print(f"Text: {text}")
print(f"Sentiment Score: {sentiment_score}")
print(f"Sentiment: {sentiment}")
print() # Sentiment Analysis with Logistic Regression
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report
corpus=[
"I love this product!",
"This is the worst service.",
"I am happy with my purchase.",
"The quality is terrible.",
"Awesome product, very satisfied!",
"Horrible quality, completely broken.",
"Great item, highly recommended.",
"Disastrous experience, bad support."
]
labels=[1,0,1,0,1,0,1,0]
X_train_text, X_test_text, y_train, y_test = train_test_split(corpus, labels, test_size=0.25, random_state=42, stratify=labels)
vectorizer=TfidfVectorizer()
X_train=vectorizer.fit_transform(X_train_text)
X_test=vectorizer.transform(X_test_text)
model=LogisticRegression()
model.fit(X_train, y_train)
y_pred=model.predict(X_test)
accuracy=accuracy_score(y_test, y_pred)
report=classification_report(y_test, y_pred, zero_division=0)
print(f"Accuracy: {accuracy}")
print("Classification Report:")
print(report) # Sentiment analysis with BERT Tokenizer & Keras
import numpy as np
import tensorflow as tf
from transformers import BertTokenizer
from sklearn.model_selection import train_test_split
corpus = [
"I love this product!",
"This is the worst service.",
"I am happy with my purchase.",
"The quality is terrible."
]
labels = [1, 0, 1, 0]
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
X = tokenizer(corpus, padding=True, truncation=True, max_length=10, return_tensors='np')
X_train, X_test, y_train, y_test = train_test_split(
X['input_ids'], labels, test_size=0.25, random_state=42
)
model = tf.keras.Sequential([
tf.keras.layers.Embedding(input_dim=tokenizer.vocab_size, output_dim=64),
tf.keras.layers.GlobalAveragePooling1D(),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(2)
])
# Use learning_rate=0.01 for training from scratch
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=0.01),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy']
)
# Train for 15 epochs
model.fit(X_train, np.array(y_train), epochs=15, batch_size=8, validation_data=(X_test, np.array(y_test)))
# Predict
new_text = ["The product is excellent and I love it."]
new_text_enc = tokenizer(new_text, padding=True, truncation=True, max_length=10, return_tensors='np')
prediction = model.predict(new_text_enc['input_ids'])
print("\nPrediction:", "Positive" if np.argmax(prediction) == 1 else "Negative")