Ready to build your first NLP model? Let's analyze sentiment!
Sentiment Analysis is the process of predicting whether a piece of text expresses a positive or negative emotion. It's widely used by companies to automatically gauge customer feedback.
We'll use IMDB movie reviews as our dataset. Here is how our pipeline will look:
TfidfVectorizer to convert words to numbers.Despite its name, logistic regression is a classifier. It computes a weighted sum of the input features, adds a bias, and passes the result through the sigmoid function 1 / (1 + e^-z), which squashes any number into the range 0 to 1. That output is read as the probability that the review is positive. With TF-IDF features there is one weight per vocabulary word. Training adjusts the weights so that positive words such as "excellent" get positive weights and negative words such as "awful" get negative weights. This is why the model is easy to inspect: you can sort the weights and read what it learned.
Here is the whole flow in compact form. This sketch uses a few hand-written reviews; the structure is identical for the real dataset.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
texts = [
"a wonderful, moving film", "brilliant acting and a great story",
"I loved every minute", "an excellent and clever script",
"dull, slow and boring", "terrible acting and a weak plot",
"I hated this movie", "a waste of time, awful",
]
labels = [1, 1, 1, 1, 0, 0, 0, 0] # 1 = positive, 0 = negative
X_train, X_test, y_train, y_test = train_test_split(
texts, labels, test_size=0.25, random_state=0, stratify=labels)
vectorizer = TfidfVectorizer(ngram_range=(1, 2))
X_train_vec = vectorizer.fit_transform(X_train) # learn vocab on train only
X_test_vec = vectorizer.transform(X_test) # reuse it on test
model = LogisticRegression(max_iter=1000)
model.fit(X_train_vec, y_train)
print(accuracy_score(y_test, model.predict(X_test_vec)))With only eight reviews the accuracy figure is meaningless statistically, but the code is what you will run on thousands of reviews. Notice the discipline: fit_transform on training text, plain transform on test text.
import numpy as np
names = np.array(vectorizer.get_feature_names_out())
order = np.argsort(model.coef_[0])
print("Most negative:", names[order[:5]])
print("Most positive:", names[order[-5:]])Inspecting the top words is the quickest sanity check. If the strongest "positive" features are movie titles or actor names rather than sentiment words, the model is memorizing the training set instead of learning sentiment.
Use predict_proba to see how confident the model is. Column 1 is the probability of the positive class:
review = ["The plot was dull and the acting was terrible."]
vec = vectorizer.transform(review)
print(model.predict(vec))
print(model.predict_proba(vec).round(2))If the data contains 50 percent positive reviews, accuracy is a fair headline metric. If only 5 percent were negative, a model that always answers "positive" would score 95 percent while being useless, so also check precision, recall and the confusion matrix from the evaluation lessons. Look at the specific errors the model makes. Sarcasm ("Great, another two hours of my life gone"), negation ("not bad at all") and mixed reviews are typical failures of a bag-of-words approach, since it cannot understand context. Bigrams help with some negation; handling sarcasm properly needs neural language models, which come later in the platform.
fit on the vectorizer with test texts included.transform. It expects a list of strings, which is why the challenge wraps the review in square brackets.ConvergenceWarning means raising max_iter or scaling the features.Once your model is trained, it's time to test it with your own words!
model and a fitted vectorizer named vectorizer.my_review = ["The plot was dull and the acting was terrible."]my_review_vectorized = vectorizer.transform(my_review)prediction = model.predict(my_review_vectorized)