How to do sentiment analysis in Python

Learn how to do sentiment analysis in Python. Discover different methods, tips, real-world applications, and how to debug common errors.

How to do sentiment analysis in Python
Published on: 
Thu
Feb 12, 2026
Updated on: 
Tue
Feb 24, 2026
The Replit Team Logo Image
The Replit Team

Sentiment analysis in Python lets you gauge public opinion from text. It's a powerful technique to interpret customer feedback, social media trends, and market sentiment with just a few lines of code.

In this article, you'll explore key techniques and practical tips. You'll see real-world applications and get advice to debug your sentiment analysis models for accurate and reliable performance.

Using TextBlob for quick sentiment analysis

from textblob import TextBlob

text = "I really enjoyed the movie. It was absolutely fantastic!"
analysis = TextBlob(text)
print(f"Polarity: {analysis.sentiment.polarity}, Subjectivity: {analysis.sentiment.subjectivity}")--OUTPUT--Polarity: 0.9, Subjectivity: 1.0

The TextBlob library simplifies sentiment analysis by abstracting away complex natural language processing. After creating a TextBlob object with your text, you can access the sentiment scores directly through the sentiment property. This returns two key metrics:

  • Polarity: A value between -1.0 (very negative) and 1.0 (very positive) that indicates the emotional leaning of the text.
  • Subjectivity: A value from 0.0 (very objective) to 1.0 (very subjective) that measures whether the text expresses an opinion or a factual statement.

In the example, the high polarity score of 0.9 reflects the enthusiastic praise, while the 1.0 subjectivity score confirms the text is purely opinion-based.

Basic sentiment analysis techniques

While TextBlob is a great starting point, you'll find that other approaches offer more control and accuracy for complex sentiment analysis tasks.

Using NLTK's VADER sentiment analyzer

import nltk
nltk.download('vader_lexicon', quiet=True)
from nltk.sentiment.vader import SentimentIntensityAnalyzer

sid = SentimentIntensityAnalyzer()
text = "The food was delicious, but the service was terrible."
print(sid.polarity_scores(text))--OUTPUT--{'neg': 0.253, 'neu': 0.451, 'pos': 0.296, 'compound': 0.1779}

For more nuanced analysis, you can use NLTK's VADER (Valence Aware Dictionary and sEntiment Reasoner). It's a model specifically tuned for the kind of language found on social media. The polarity_scores() method returns a dictionary containing four distinct scores.

  • neg, neu, and pos: These represent the proportion of text that is negative, neutral, and positive.
  • compound: This is a single, normalized score from -1 to +1 that summarizes the overall sentiment.

This breakdown is particularly useful for complex sentences with mixed emotions, like the example provided, where it captures both the positive and negative elements.

Creating a simple rule-based sentiment analyzer

def simple_sentiment(text):
   positive_words = ['good', 'great', 'excellent', 'love', 'happy']
   negative_words = ['bad', 'terrible', 'awful', 'hate', 'sad']
   words = text.lower().split()
   score = sum(1 for w in words if w in positive_words) - sum(1 for w in words if w in negative_words)
   return "Positive" if score > 0 else "Negative" if score < 0 else "Neutral"

print(simple_sentiment("I love this great product despite some bad reviews"))--OUTPUT--Positive

Building a rule-based analyzer gives you complete control over the logic. This approach relies on predefined lists of words, or lexicons, to classify sentiment. It’s a transparent method, though its effectiveness depends entirely on how comprehensive your word lists are.

  • The simple_sentiment function defines its own positive_words and negative_words lists.
  • It calculates a score by counting words from the positive list and subtracting the count of words from the negative list.
  • A final score greater than zero returns "Positive", while a score less than zero returns "Negative".

Using spaCy with sentiment extensions

import spacy
from spacytextblob.spacytextblob import SpacyTextBlob

nlp = spacy.load('en_core_web_sm')
nlp.add_pipe('spacytextblob')
doc = nlp("This product exceeded my expectations. Highly recommended!")
print(f"Polarity: {doc._.blob.polarity}, Subjectivity: {doc._.blob.subjectivity}")--OUTPUT--Polarity: 0.75, Subjectivity: 0.8

The spaCy library offers a powerful framework for building custom natural language processing pipelines. While it doesn't include a built-in sentiment analyzer, you can easily extend its functionality. This example uses spacytextblob to integrate TextBlob's simple sentiment analysis directly into the spaCy workflow.

  • You add the component to your pipeline with nlp.add_pipe('spacytextblob') after loading a model.
  • Once the text is processed into a doc object, the sentiment scores become available.
  • You can access them through the custom doc._.blob attribute, which provides the familiar polarity and subjectivity metrics.

Advanced sentiment analysis approaches

When off-the-shelf solutions like TextBlob or VADER aren't quite enough, you can turn to advanced techniques for more power and domain-specific accuracy.

Using transformers with the pipeline API

from transformers import pipeline

sentiment_analyzer = pipeline("sentiment-analysis")
result = sentiment_analyzer("The plot was predictable, but the acting was superb.")
print(result)--OUTPUT--[{'label': 'POSITIVE', 'score': 0.9743}]

The transformers library offers an easy entry point to state-of-the-art models through its pipeline API. Calling pipeline("sentiment-analysis") automatically downloads and configures a powerful, pre-trained model, abstracting away the complex setup that's usually required for transformer-based natural language processing.

  • The resulting sentiment_analyzer object acts like a function that you can pass your text directly into.
  • It returns a dictionary containing a sentiment label and a confidence score, which provides a more sophisticated analysis than simpler lexical methods.

Fine-tuning a pre-trained model for domain-specific analysis

from transformers import AutoModelForSequenceClassification, AutoTokenizer
from datasets import load_dataset

model_name = "distilbert-base-uncased"
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)
tokenizer = AutoTokenizer.from_pretrained(model_name)
dataset = load_dataset("imdb", split="train[:100]")
print(f"Loaded model and {len(dataset)} samples for fine-tuning")--OUTPUT--Loaded model and 100 samples for fine-tuning

Fine-tuning lets you adapt a powerful, general-purpose model for a specific task, like analyzing movie reviews. This code sets the stage by loading a pre-trained model (distilbert-base-uncased) and its corresponding tokenizer. This ensures your text is processed in a way the model understands.

  • You use AutoModelForSequenceClassification to get a model ready for classification tasks.
  • The model is configured for binary sentiment (e.g., positive/negative) with num_labels=2.
  • load_dataset pulls in domain-specific data—in this case, imdb movie reviews—to retrain the model on.

Creating an ensemble model for improved accuracy

from sklearn.ensemble import VotingClassifier
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import MultinomialNB

vectorizer = CountVectorizer()
ensemble = VotingClassifier(estimators=[
   ('lr', LogisticRegression()),
   ('nb', MultinomialNB())
])
print("Ensemble model created for robust sentiment predictions")--OUTPUT--Ensemble model created for robust sentiment predictions

An ensemble model improves prediction accuracy by combining the strengths of several different models. This approach is like asking a panel of experts for their opinion instead of just one. The VotingClassifier aggregates the results from each model in the ensemble to make a final, more robust prediction.

  • The code sets up an ensemble with two distinct models: a LogisticRegression classifier and a MultinomialNB classifier.
  • Before the models can analyze text, CountVectorizer converts the words into numerical features they can understand.

Move faster with Replit

Replit is an AI-powered development platform that transforms natural language into working applications. With Replit Agent, you can turn the sentiment analysis concepts from this article into complete apps—with databases, APIs, and deployment—directly from a description.

For the sentiment analysis techniques we've explored, Replit Agent can turn them into production tools:

  • Build a social media monitoring dashboard that tracks brand sentiment in real time.
  • Create a customer feedback analyzer that categorizes product reviews as positive, negative, or neutral.
  • Deploy a specialized analysis tool for a specific industry, like movies or restaurants, by fine-tuning a model on domain-specific data.

You can take these ideas from concept to a working application without writing boilerplate code. Describe your app idea and let Replit Agent write, test, and deploy it for you.

Common errors and challenges

Even with powerful tools, you can run into common issues that skew your sentiment analysis results, so it's important to know what to watch for.

Forgetting to install required TextBlob dependencies

While TextBlob is easy to install, it relies on additional data packages, or corpora, for accurate analysis. If you forget to download them, the library may fall back to less effective patterns, leading to poor results. You can fetch the necessary data by running the command python -m textblob.download_corpora in your terminal.

Addressing negation handling in sentiment analysis

A frequent challenge is handling negation. Simple, rule-based models often struggle with phrases like "not good" because they might register the word "good" and incorrectly assign a positive score. This completely flips the intended meaning. More sophisticated tools like NLTK's VADER are specifically designed to recognize negation and other linguistic nuances, providing a more accurate interpretation.

Preprocessing text properly for accurate sentiment analysis

The quality of your input text directly impacts the quality of your sentiment analysis. Raw text is often messy, so preprocessing is a critical step to clean it up before feeding it to a model. Proper preprocessing helps reduce noise and allows the model to focus on the words that carry the most sentiment.

  • Converting to lowercase: This ensures that words like "Good" and "good" are treated as the same word.
  • Removing punctuation: Characters like commas, periods, and exclamation points can interfere with word tokenization and analysis.
  • Removing stop words: Common words such as "the," "a," and "is" usually don't carry sentiment and can be filtered out.

Skipping these steps can introduce inconsistencies and lead to less reliable sentiment scores.

Forgetting to install required TextBlob dependencies

This oversight can produce surprisingly inaccurate results. Even with code that appears correct, TextBlob might fail to capture obvious sentiment if its corpora are missing. Take a look at the following example, which processes a clearly positive sentence.

from textblob import TextBlob

text = "The movie was fantastic!"
analysis = TextBlob(text)
print(f"Polarity: {analysis.sentiment.polarity}")

Without its required data packages, TextBlob fails to recognize the positive sentiment in the text, leading to a misleadingly neutral score. The following example first shows this incorrect output, then demonstrates the proper setup.

import nltk
from textblob import TextBlob

# Download required NLTK data
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')

text = "The movie was fantastic!"
analysis = TextBlob(text)
print(f"Polarity: {analysis.sentiment.polarity}")

Without its underlying NLTK data, TextBlob can't properly parse sentences, leading to inaccurate sentiment scores. The corrected code fixes this by explicitly downloading the punkt tokenizer and averaged_perceptron_tagger corpora using nltk.download(). You should run this setup in any new environment to ensure TextBlob has the resources it needs for reliable analysis. This simple step prevents the library from misinterpreting clear sentiment and returning neutral scores.

Addressing negation handling in sentiment analysis

Simple sentiment analysis models often stumble over negation. By analyzing words in isolation, a model might see a positive term but miss the negative context, completely misreading the user's intent. The code below shows this common pitfall in action.

from textblob import TextBlob

text = "I am not happy with this product at all."
words = text.split()
positive_words = sum(1 for word in words if TextBlob(word).sentiment.polarity > 0)
negative_words = sum(1 for word in words if TextBlob(word).sentiment.polarity < 0)
print(f"Positive words: {positive_words}, Negative words: {negative_words}")

The code processes each word in isolation after using text.split(), causing it to register "happy" as positive while missing the negation. The following example demonstrates a more effective way to handle this by analyzing the sentence as a whole.

from textblob import TextBlob

text = "I am not happy with this product at all."
# Analyze the full sentence to capture context and negations
analysis = TextBlob(text)
print(f"Full text polarity: {analysis.sentiment.polarity}")

The corrected code works because it feeds the entire sentence to TextBlob, allowing it to recognize the negation in "not happy." When you analyze words one by one, the model sees "happy" as positive and misses the context. This mistake is common, so always process the full text to accurately capture complex phrases. This ensures you don't misinterpret sentiment in user feedback or social media comments where negation and sarcasm are frequent.

Preprocessing text properly for accurate sentiment analysis

Failing to preprocess text is a common pitfall that can lead to misleading sentiment scores. Punctuation, inconsistent casing, and even emoticons can confuse a model. The code below demonstrates how unprocessed text can cause a simple library like TextBlob to misinterpret sentiment.

from textblob import TextBlob

text = "This product is AMAZING!!! I love it :) <3"
analysis = TextBlob(text)
print(f"Polarity: {analysis.sentiment.polarity}")

The code passes raw text with uppercase letters and emoticons directly to TextBlob. This noise interferes with the analysis, producing a misleading polarity score. The following example demonstrates a more effective approach for an accurate reading.

import re
from textblob import TextBlob

text = "This product is AMAZING!!! I love it :) <3"
# Remove special characters and normalize
clean_text = re.sub(r'[^\w\s]', '', text.lower())
analysis = TextBlob(clean_text)
print(f"Polarity: {analysis.sentiment.polarity}")

The corrected code cleans the text before analysis. It converts the string to lowercase with text.lower() and uses a regular expression, re.sub(r'[^\w\s]', '', ...), to strip away punctuation and symbols. This normalization ensures the model focuses only on the words carrying sentiment, leading to a more accurate polarity score. This is especially important when working with informal text from social media or customer reviews, which often contains noise that can skew results.

Real-world applications

Beyond debugging models, sentiment analysis helps you extract valuable insights from real-world data like customer reviews and track trends over time.

Analyzing customer reviews with TextBlob

With TextBlob, you can iterate through a list of customer reviews to classify each one and calculate an overall sentiment score.

from textblob import TextBlob

reviews = [
   "This product is amazing! I love it.",
   "Decent quality, but a bit expensive.",
   "Terrible experience, would not recommend.",
   "Works as expected, good value.",
   "Disappointed with the durability."
]

polarities = [TextBlob(review).sentiment.polarity for review in reviews]
for i, (review, polarity) in enumerate(zip(reviews, polarities)):
   sentiment = "Positive" if polarity > 0.1 else "Negative" if polarity < -0.1 else "Neutral"
   print(f"Review {i+1}: {sentiment} ({polarity:.2f}) - {review}")
print(f"\nAverage sentiment polarity: {sum(polarities)/len(polarities):.2f}")

This script efficiently processes a batch of reviews to gauge overall customer opinion. It uses a list comprehension to generate a polarity score for every review in one go, storing them in the polarities list.

  • The code then uses zip to pair each review with its corresponding polarity score for easy processing.
  • It classifies sentiment using a conditional statement that creates a neutral buffer zone for scores between -0.1 and 0.1.

Finally, it calculates the average polarity, providing a single metric that summarizes the entire dataset.

Analyzing sentiment trends in product reviews over time

You can also use pandas to organize reviews by date, allowing you to analyze how sentiment changes from one month to the next.

from textblob import TextBlob
import pandas as pd

reviews_data = {
   'Month': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
   'Reviews': [
       "This product is terrible, don't buy it",
       "Some improvements but still not great",
       "Getting better, some issues remain",
       "Good product, highly recommended",
       "Excellent product, exceeded expectations!"
   ]
}

df = pd.DataFrame(reviews_data)
df['Sentiment'] = df['Reviews'].apply(lambda x: TextBlob(x).sentiment.polarity)
print(df[['Month', 'Sentiment']])
print(f"\nSentiment trend: {'+' if df['Sentiment'].is_monotonic_increasing else '-'}")

This script combines pandas with TextBlob to measure sentiment progression. It first structures review data into a pandas DataFrame, which acts like a powerful spreadsheet within your code.

  • The .apply() method runs a lambda function on each review to calculate its polarity score.
  • These scores are then stored in a new 'Sentiment' column, letting you track changes over time.

Finally, the code uses .is_monotonic_increasing to quickly check if customer opinion is trending upward across the months.

Get started with Replit

Turn what you've learned into a real application. Describe your idea to Replit Agent, like "build a dashboard to analyze review sentiment" or "create a script that scores social media comments and finds the average."

Replit Agent writes the code, tests for errors, and deploys the app directly from your description. Start building with Replit.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

Get started for free

Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.