Build a Text Emotion Detector

Train a machine learning model to detect emotions in text using Python.

Introduction

30 Second Summary

Every text message you read carries an emotion. You instinctively know when a friend is happy or worried just from their words.

In this project, you will build a Python program that predicts emotions from any English sentence. You'll train a machine learning model on 16,000 real text messages, then use it to detect joy, sadness, anger, fear, love, and surprise.

What You'll Build

A command-line emotion detector that reads any English sentence and predicts the emotion behind it using scikit-learn and Python.

By the end of this project, you'll have:

  • A working Python script (emotion_detector.py) that loads real-world data, trains a Logistic Regression model, and predicts emotions from text.
  • Hands-on experience with the full ML pipeline: loading data, transforming text into numbers, training a model, and evaluating results.
  • A reusable predict_emotion() function that analyzes any text you type and shows confidence scores for all 6 emotions.
  • Secret Mission: Compare multiple ML algorithms (Naive Bayes, Random Forest) and find which one detects emotions best.

Are there any prerequisites?

None. This project is designed for complete beginners. You'll learn the Python basics you need as you build.

Load the Emotion Dataset

Your environment is set up and ready to go. Now it's time to give your program something to learn from.

Machine learning models learn patterns from examples, just like how you learn to recognize emotions in text by reading thousands of messages over your lifetime. In this step, you'll load a dataset of 16,000 real text messages that are each labeled with an emotion, then explore what that data looks like.

In this step, get ready to:
  • Create your Python file and load the emotion dataset from Hugging Face.
  • Convert the data into a format you can explore and add readable emotion names.
  • Run your script and see what the training data looks like.
Create your Python file and load the data

Every ML project starts with data. You'll load a pre-labeled dataset from Hugging Face, a platform that hosts thousands of free datasets for machine learning.

  • In VS Code, create a new file by clicking File in the top menu bar.
  • Click New File.
  • Save the file immediately by pressing Cmd+S (macOS) or Ctrl+S (Windows).
  • Navigate to your emotion-detector folder, name the file emotion_detector.py, and click Save.
  • Copy the following code into emotion_detector.py:
from datasets import load_dataset
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# Load the emotion dataset from Hugging Face
print("Loading emotion dataset...")
dataset = load_dataset("dair-ai/emotion", "split")
print(f"Training examples: {len(dataset['train'])}")
print(f"Test examples: {len(dataset['test'])}")

What does this code do?

The first five lines import all the libraries you'll need throughout this project. You won't use all of them in this step, but importing everything upfront keeps your code organized.

  • load_dataset fetches the emotion dataset directly from Hugging Face's servers.
  • The "split" argument tells it to load the pre-split version with separate training and test sets.
  • The print statements confirm how many examples loaded successfully.

What is Hugging Face?

Hugging Face is a platform that hosts free datasets and pre-trained models for machine learning. The dair-ai/emotion dataset contains real text messages from Twitter, each labeled with one of six emotions: sadness, joy, love, anger, fear, or surprise.

  • Save emotion_detector.py by pressing Cmd+S (macOS) or Ctrl+S (Windows).
Convert the data to a pandas DataFrame and explore it

The raw dataset uses numbers (0 through 5) to represent emotions. You'll convert it to a pandas DataFrame and map those numbers to readable emotion names so you can see what you're working with.

  • Add the following code below the existing code in emotion_detector.py:
# Convert to pandas DataFrames for exploration
train_df = pd.DataFrame(dataset["train"])
test_df = pd.DataFrame(dataset["test"])

# Map numeric labels to emotion names
emotion_labels = {0: "sadness", 1: "joy", 2: "love", 3: "anger", 4: "fear", 5: "surprise"}
train_df["emotion"] = train_df["label"].map(emotion_labels)
test_df["emotion"] = test_df["label"].map(emotion_labels)

# Explore the data
print("\n--- Dataset Preview ---")
print(train_df.head(10))
print("\n--- Emotion Distribution ---")
print(train_df["emotion"].value_counts())

What does this code do?

  • pd.DataFrame() converts the Hugging Face dataset into a pandas table. This makes it easy to explore, filter, and manipulate.
  • emotion_labels is a dictionary that maps each number to its emotion name. For example, 0 becomes "sadness" and 1 becomes "joy".
  • .map(emotion_labels) creates a new "emotion" column with readable names instead of numbers.
  • .head(10) shows the first 10 rows so you can preview the data.
  • .value_counts() counts how many examples exist for each emotion. This tells you if the dataset is balanced.

What is a DataFrame?

A DataFrame is a table of data with rows and columns, similar to a spreadsheet. Each row is one text message, and the columns hold the text content, the numeric label, and the emotion name.

Pandas DataFrames make it easy to slice, filter, and analyze data with simple Python commands.

Run your script to see the data
  • Save emotion_detector.py by pressing Cmd+S (macOS) or Ctrl+S (Windows).
  • Run your script in the terminal by running this command:
python3 emotion_detector.py

You should see three things printed: the number of training and test examples, a preview of the first 10 rows showing text and emotions, and a count of how many messages belong to each emotion.

What should I see?

The dataset loads from the internet the first time you run it, so you may see a download progress bar. After loading, you'll see 16,000 training examples and 2,000 test examples.

The preview table shows columns for text, label, and emotion. The distribution shows that joy and sadness have the most examples, while surprise has the fewest.

Seeing a ModuleNotFoundError?

This means your virtual environment isn't active. Check that your terminal prompt starts with (venv). If not, activate it by running:

source venv/bin/activate

Then try running the script again. If the error persists, reinstall the packages with pip install scikit-learn pandas datasets.

Help me fix this ModuleNotFoundError

✔️ Awesome, I've got everything!

Great. Double check you've saved emotion_detector.py and your terminal shows the dataset loaded successfully.

ⓧ I'd like to double check the full code

Here's the complete emotion_detector.py file so far:

from datasets import load_dataset
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# Load the emotion dataset from Hugging Face
print("Loading emotion dataset...")
dataset = load_dataset("dair-ai/emotion", "split")
print(f"Training examples: {len(dataset['train'])}")
print(f"Test examples: {len(dataset['test'])}")

# Convert to pandas DataFrames for exploration
train_df = pd.DataFrame(dataset["train"])
test_df = pd.DataFrame(dataset["test"])

# Map numeric labels to emotion names
emotion_labels = {0: "sadness", 1: "joy", 2: "love", 3: "anger", 4: "fear", 5: "surprise"}
train_df["emotion"] = train_df["label"].map(emotion_labels)
test_df["emotion"] = test_df["label"].map(emotion_labels)

# Explore the data
print("\n--- Dataset Preview ---")
print(train_df.head(10))
print("\n--- Emotion Distribution ---")
print(train_df["emotion"].value_counts())

Your data is loaded and you can see what emotions look like in text form. Next up, you'll transform these words into numbers that a machine learning model can actually learn from.

Transform Text into Numbers

In the previous step, you loaded 16,000 text messages and explored how emotions are distributed across your dataset. Your model now needs to learn from this text. But there's a problem.

Machine learning models only understand numbers, not words. Before training, you need to convert every text message into a numerical representation that captures which words matter most for each emotion.

In this step, get ready to:
  • Separate text and labels into training and test variables.
  • Apply TF-IDF vectorization to convert words into numbers.
  • Run the script and observe the transformation results.
Separate the text and labels

Your DataFrame has multiple columns, but the model only needs two things: the input text and the emotion label it should predict. You need to pull these out into separate variables for training and testing.

  • In emotion_detector.py, scroll to the bottom of your file (below the print(train_df["emotion"].value_counts()) line).
  • Add this code to extract the text and labels into separate variables:
# Prepare data for training
X_train = train_df["text"]
y_train = train_df["label"]
X_test = test_df["text"]
y_test = test_df["label"]

What does this code do?

In machine learning, X is the conventional name for input data (what the model sees) and y is the conventional name for the target (what the model predicts).

You create separate pairs for training (16,000 examples the model learns from) and testing (2,000 examples it has never seen, used to check how well it learned).

  • Save emotion_detector.py.
  • You won't see a change yet. The next chunk transforms this data with TF-IDF.
Apply TF-IDF vectorization

Now you'll convert those text strings into numbers. TF-IDF (Term Frequency-Inverse Document Frequency) scores each word by how important it is. Words that appear often in one emotion but rarely in others get higher scores.

  • Add this code directly below the data preparation block you just wrote:
# Transform text to numbers using TF-IDF
print("\nTransforming text to numbers...")
vectorizer = TfidfVectorizer(max_features=5000, stop_words="english")
X_train_tfidf = vectorizer.fit_transform(X_train)
X_test_tfidf = vectorizer.transform(X_test)
print(f"Vocabulary size: {len(vectorizer.vocabulary_)}")
print(f"Feature matrix shape: {X_train_tfidf.shape}")

What does this code do?

  • TfidfVectorizer(max_features=5000, stop_words="english") creates a vectorizer that keeps the 5,000 most important words and ignores common English words like "the" and "is".
  • fit_transform(X_train) learns the vocabulary from training data AND converts it to numbers in one step.
  • transform(X_test) converts test data using the same vocabulary (no new learning). This prevents the model from "cheating" by peeking at test data.

Why fit_transform on training but only transform on test?

The vectorizer needs to learn its vocabulary from training data only. If it also learned from test data, your accuracy score would be artificially high. In real-world ML, you never let your model see the test set during setup.

  • Save emotion_detector.py.
Run and observe the transformation

Time to see the transformation in action. When you run the script, you'll see the vocabulary size and the shape of your feature matrix. This is where "text" becomes "math" that a model can learn from.

  • Run the script in your terminal by running this command:
python3 emotion_detector.py
  • Look for the new output at the bottom. You should see Vocabulary size: showing a number near 5000 and Feature matrix shape: showing (16000, 5000).

What do these numbers mean?

The feature matrix shape (16000, 5000) means you have 16,000 training examples, each represented by 5,000 numbers. Each number is the TF-IDF score for one word in that message.

Most of those 5,000 numbers will be zero for any given message (a single message only uses a handful of words). This sparse structure is what makes TF-IDF efficient for text.

Not seeing the new output?

  • Make sure you saved emotion_detector.py before running the command.
  • Check that your new code is below the existing print(train_df["emotion"].value_counts()) line, not inside it.
  • Confirm your virtual environment is still active. You should see (venv) at the start of your terminal prompt.

Why isn't my TF-IDF output showing up when I run the script?

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Here's what your complete emotion_detector.py should look like at this point:

from datasets import load_dataset
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# Load the emotion dataset from Hugging Face
print("Loading emotion dataset...")
dataset = load_dataset("dair-ai/emotion", "split")
print(f"Training examples: {len(dataset['train'])}")
print(f"Test examples: {len(dataset['test'])}")

# Convert to pandas DataFrames for exploration
train_df = pd.DataFrame(dataset["train"])
test_df = pd.DataFrame(dataset["test"])

# Map numeric labels to emotion names
emotion_labels = {0: "sadness", 1: "joy", 2: "love", 3: "anger", 4: "fear", 5: "surprise"}
train_df["emotion"] = train_df["label"].map(emotion_labels)
test_df["emotion"] = test_df["label"].map(emotion_labels)

# Explore the data
print("\n--- Dataset Preview ---")
print(train_df.head(10))
print("\n--- Emotion Distribution ---")
print(train_df["emotion"].value_counts())

# Prepare data for training
X_train = train_df["text"]
y_train = train_df["label"]
X_test = test_df["text"]
y_test = test_df["label"]

# Transform text to numbers using TF-IDF
print("\nTransforming text to numbers...")
vectorizer = TfidfVectorizer(max_features=5000, stop_words="english")
X_train_tfidf = vectorizer.fit_transform(X_train)
X_test_tfidf = vectorizer.transform(X_test)
print(f"Vocabulary size: {len(vectorizer.vocabulary_)}")
print(f"Feature matrix shape: {X_train_tfidf.shape}")

Your text data is now a matrix of numbers that a machine learning model can learn from. Next up, you'll train a Logistic Regression model on these features and see how accurately it predicts emotions.

Train and Evaluate Your Model

Your text data is now represented as numbers that a machine learning model can understand. The TF-IDF transformation gave each word an importance score based on how uniquely it appears across different emotions.

Now it is time to teach a model to recognize patterns in those numbers. You will train a Logistic Regression classifier on your 16,000 training examples, then test it on 2,000 examples it has never seen before to measure how well it learned.

In this step, get ready to:
  • Train a Logistic Regression model on your TF-IDF features.
  • Evaluate the model's accuracy on unseen test data.
  • Analyze per-emotion performance using a classification report.
Train a Logistic Regression model

Logistic Regression learns which word patterns correspond to which emotions by finding mathematical boundaries between the 6 emotion categories. It is fast, interpretable, and performs surprisingly well on text classification tasks.

  • In emotion_detector.py, scroll to the bottom of your file (below the line that prints the feature matrix shape).
  • Add the training code by copying the following below your existing code:
# Train the model
print("\nTraining the model...")
model = LogisticRegression(max_iter=1000, random_state=42)
model.fit(X_train_tfidf, y_train)
print("Model trained!")

What does this code do?

LogisticRegression(max_iter=1000, random_state=42) creates a new model instance. The default max_iter is 100, but we increase it to 1000 to give the model enough iterations to converge on our 5,000-feature dataset.

random_state=42 makes results reproducible. Every time you run this script, the model will produce the same results.

model.fit(X_train_tfidf, y_train) is where the actual learning happens. The model examines all 16,000 training examples and learns which TF-IDF word patterns predict each emotion.

  • Save emotion_detector.py.
  • You will not see a change yet because the script needs to be run. The next chunk adds evaluation, then you will run everything together.
Evaluate model accuracy

Training a model is only half the job. You need to test it on data it has never seen to know if it actually learned useful patterns or just memorized the training set.

  • In emotion_detector.py, add the following evaluation code directly below the print("Model trained!") line:
# Evaluate the model
y_pred = model.predict(X_test_tfidf)
accuracy = accuracy_score(y_test, y_pred)
print(f"\n--- Model Performance ---")
print(f"Accuracy: {accuracy:.2%}")
print("\n--- Per-Emotion Performance ---")
print(classification_report(y_test, y_pred, target_names=list(emotion_labels.values())))

What does this code do?

model.predict(X_test_tfidf) asks the trained model to predict emotions for the 2,000 test examples it has never seen before. These predictions are stored in y_pred.

accuracy_score(y_test, y_pred) compares the model's predictions against the correct answers and calculates what percentage it got right.

classification_report breaks down performance for each individual emotion. It shows precision (how often the model is correct when it predicts an emotion), recall (how many examples of that emotion it finds), and F1-score (a balanced combination of both).

  • Save emotion_detector.py.
  • You will run the script in the next substep to see your results.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before running it.

ⓧ I'd like to double check the full code

Here is the complete emotion_detector.py file up to this point:

from datasets import load_dataset
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# Load the emotion dataset from Hugging Face
print("Loading emotion dataset...")
dataset = load_dataset("dair-ai/emotion", "split")
print(f"Training examples: {len(dataset['train'])}")
print(f"Test examples: {len(dataset['test'])}")

# Convert to pandas DataFrames for exploration
train_df = pd.DataFrame(dataset["train"])
test_df = pd.DataFrame(dataset["test"])

# Map numeric labels to emotion names
emotion_labels = {0: "sadness", 1: "joy", 2: "love", 3: "anger", 4: "fear", 5: "surprise"}
train_df["emotion"] = train_df["label"].map(emotion_labels)
test_df["emotion"] = test_df["label"].map(emotion_labels)

# Explore the data
print("\n--- Dataset Preview ---")
print(train_df.head(10))
print("\n--- Emotion Distribution ---")
print(train_df["emotion"].value_counts())

# Prepare data for training
X_train = train_df["text"]
y_train = train_df["label"]
X_test = test_df["text"]
y_test = test_df["label"]

# Transform text to numbers using TF-IDF
print("\nTransforming text to numbers...")
vectorizer = TfidfVectorizer(max_features=5000, stop_words="english")
X_train_tfidf = vectorizer.fit_transform(X_train)
X_test_tfidf = vectorizer.transform(X_test)
print(f"Vocabulary size: {len(vectorizer.vocabulary_)}")
print(f"Feature matrix shape: {X_train_tfidf.shape}")

# Train the model
print("\nTraining the model...")
model = LogisticRegression(max_iter=1000, random_state=42)
model.fit(X_train_tfidf, y_train)
print("Model trained!")

# Evaluate the model
y_pred = model.predict(X_test_tfidf)
accuracy = accuracy_score(y_test, y_pred)
print(f"\n--- Model Performance ---")
print(f"Accuracy: {accuracy:.2%}")
print("\n--- Per-Emotion Performance ---")
print(classification_report(y_test, y_pred, target_names=list(emotion_labels.values())))
Run and analyze results
  • Run your script by entering this command in your terminal:
python3 emotion_detector.py

After the dataset loads and the TF-IDF transformation runs, you should see your model's overall accuracy (around 87%) followed by a detailed per-emotion breakdown.

What should I see?

Your output will include an overall accuracy percentage and a table with columns for precision, recall, f1-score, and support for each of the 6 emotions.

You will likely notice that "joy" and "sadness" have the highest scores because they have the most training examples. "Love" and "surprise" tend to score lower because they have fewer examples and can overlap with other emotions.

Seeing an error when you run the script?

  • If you see ModuleNotFoundError, make sure your virtual environment is activated. Run source venv/bin/activate and try again.
  • If you see NameError: name 'model' is not defined, check that the training code from the first substep is above the evaluation code. Order matters in Python.
  • If the script seems to hang during training, give it a few seconds. The model is processing 16,000 examples across 5,000 features.

Help me debug my emotion detector script

Your model can now classify emotions with solid accuracy. Next up, you will build a reusable prediction function so you can test the model on any sentence you type.

Build Your Prediction Function

Your model is trained and you know it works. It scored ~87% accuracy across 6 different emotions. Now it's time to make it useful.

In this step, you'll wrap your trained model into a reusable function that takes any sentence and predicts its emotion. This is the part where your project goes from "it works on test data" to "I can type anything and get a prediction."

In this step, get ready to:
  • Write a reusable prediction function with confidence scores.
  • Test your model on custom sentences covering all 6 emotions.
  • Run the complete program end-to-end.
Write a predict_emotion() function

Right now, your model can only predict on pre-loaded test data. A function wraps the prediction logic into something you can call on any text string, anytime.

  • In emotion_detector.py, scroll to the very bottom of the file (after the classification report prints).
  • Add the prediction function by copying this code at the end of your file:

# Prediction function
def predict_emotion(text):
    text_tfidf = vectorizer.transform([text])
    prediction = model.predict(text_tfidf)[0]
    probabilities = model.predict_proba(text_tfidf)[0]
    predicted_emotion = emotion_labels[prediction]
    confidence = probabilities[prediction]
    print(f"\nText: \"{text}\"")
    print(f"Predicted Emotion: {predicted_emotion} (confidence: {confidence:.2%})")
    print("All emotions:")
    for label_id, emotion in emotion_labels.items():
        print(f"  {emotion}: {probabilities[label_id]:.2%}")
    return predicted_emotion

What does this function do?

This function takes a raw text string through the same pipeline your training data went through.

  • vectorizer.transform([text]) converts the text into TF-IDF numbers using the same vocabulary learned during training.
  • model.predict() returns the most likely emotion label.
  • model.predict_proba() returns the confidence score for all 6 emotions, so you can see how "sure" the model is.

You won't see any output yet. The function is defined but not called. The next substep adds test sentences that call it.

Test with your own sentences

Now you'll call the function with sentences that cover all 6 emotions the model was trained on. This tests whether the model generalizes beyond the training data.

  • Add these test calls directly below the predict_emotion function:

# Try it out!
print("\n--- Try Your Own Sentences ---")
predict_emotion("I am so happy today, everything is wonderful!")
predict_emotion("I feel terrible and nothing is going right")
predict_emotion("I can't believe they would do that to me")
predict_emotion("What if something bad happens tomorrow")
predict_emotion("You mean the world to me")
predict_emotion("I never expected that to happen!")

What does each sentence test?

  • "I am so happy today..." tests joy detection.
  • "I feel terrible..." tests sadness detection.
  • "I can't believe they would do that..." tests anger detection.
  • "What if something bad happens..." tests fear detection.
  • "You mean the world to me" tests love detection.
  • "I never expected that to happen!" tests surprise detection.
  • Save emotion_detector.py.
Run the complete program

Your script now does everything end-to-end: loads data, trains the model, evaluates it, and predicts emotions on custom text. Time to run it.

  • Run your complete emotion detector by running this command:
python3 emotion_detector.py
  • Scroll to the bottom of the output. You should see a --- Try Your Own Sentences --- header followed by 6 predictions, each showing the predicted emotion, its confidence score, and a breakdown of all 6 emotion probabilities.

What should I see?

Each prediction prints the input text, the predicted emotion with a confidence percentage, and a list of all 6 emotion probabilities. For example, the "happy" sentence should predict joy with high confidence (often 80%+).

Some predictions might surprise you. The model learned patterns from Twitter data, so it may interpret sentences differently than you expect. That's part of the fun of exploring ML.

Seeing a NameError?

  • If you see NameError: name 'predict_emotion' is not defined, make sure the function definition appears ABOVE the lines that call it.
  • If you see NameError: name 'vectorizer' is not defined, make sure you didn't accidentally delete the TF-IDF section earlier in the file.
  • Check your indentation. Everything inside def predict_emotion(text): must be indented with 4 spaces.

Still stuck? Help me debug my predict_emotion function

Try experimenting with your own sentences. Change the text inside any of the predict_emotion() calls to test sarcasm, mixed emotions, or short messages. See where the model gets confused.

✔️ Awesome, I've got everything!

Great. Double check you've saved your file.

ⓧ I'd like to double check the full code

Here's the complete emotion_detector.py file. Compare it against yours:

from datasets import load_dataset
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# Load the emotion dataset from Hugging Face
print("Loading emotion dataset...")
dataset = load_dataset("dair-ai/emotion", "split")
print(f"Training examples: {len(dataset['train'])}")
print(f"Test examples: {len(dataset['test'])}")

# Convert to pandas DataFrames for exploration
train_df = pd.DataFrame(dataset["train"])
test_df = pd.DataFrame(dataset["test"])

# Map numeric labels to emotion names
emotion_labels = {0: "sadness", 1: "joy", 2: "love", 3: "anger", 4: "fear", 5: "surprise"}
train_df["emotion"] = train_df["label"].map(emotion_labels)
test_df["emotion"] = test_df["label"].map(emotion_labels)

# Explore the data
print("\n--- Dataset Preview ---")
print(train_df.head(10))
print("\n--- Emotion Distribution ---")
print(train_df["emotion"].value_counts())

# Prepare data for training
X_train = train_df["text"]
y_train = train_df["label"]
X_test = test_df["text"]
y_test = test_df["label"]

# Transform text to numbers using TF-IDF
print("\nTransforming text to numbers...")
vectorizer = TfidfVectorizer(max_features=5000, stop_words="english")
X_train_tfidf = vectorizer.fit_transform(X_train)
X_test_tfidf = vectorizer.transform(X_test)
print(f"Vocabulary size: {len(vectorizer.vocabulary_)}")
print(f"Feature matrix shape: {X_train_tfidf.shape}")

# Train the model
print("\nTraining the model...")
model = LogisticRegression(max_iter=1000, random_state=42)
model.fit(X_train_tfidf, y_train)
print("Model trained!")

# Evaluate the model
y_pred = model.predict(X_test_tfidf)
accuracy = accuracy_score(y_test, y_pred)
print(f"\n--- Model Performance ---")
print(f"Accuracy: {accuracy:.2%}")
print("\n--- Per-Emotion Performance ---")
print(classification_report(y_test, y_pred, target_names=list(emotion_labels.values())))


# Prediction function
def predict_emotion(text):
    text_tfidf = vectorizer.transform([text])
    prediction = model.predict(text_tfidf)[0]
    probabilities = model.predict_proba(text_tfidf)[0]
    predicted_emotion = emotion_labels[prediction]
    confidence = probabilities[prediction]
    print(f"\nText: \"{text}\"")
    print(f"Predicted Emotion: {predicted_emotion} (confidence: {confidence:.2%})")
    print("All emotions:")
    for label_id, emotion in emotion_labels.items():
        print(f"  {emotion}: {probabilities[label_id]:.2%}")
    return predicted_emotion


# Try it out!
print("\n--- Try Your Own Sentences ---")
predict_emotion("I am so happy today, everything is wonderful!")
predict_emotion("I feel terrible and nothing is going right")
predict_emotion("I can't believe they would do that to me")
predict_emotion("What if something bad happens tomorrow")
predict_emotion("You mean the world to me")
predict_emotion("I never expected that to happen!")

Secret mission

Compare Multiple Algorithms

Your Logistic Regression model works well, but is it the best? In this secret mission, you'll pit three different machine learning algorithms against each other to find the ultimate emotion detector.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your files to experiment further, or delete them to free up disk space.

Resources you used:

  • The emotion-detector project folder on your Desktop (contains your virtual environment, installed packages, and script).

Keep everything running

No action needed. Choose this if you want to keep experimenting with your emotion detector or try new sentences.

  • Your emotion-detector folder stays on your Desktop with all packages installed.
  • To use it again later, open Terminal, navigate to the folder, and activate the virtual environment with source venv/bin/activate.

Pause - I'll come back to this later

Since this project is entirely local and uses no running processes, there is nothing to pause. Your files sit on disk until you return.

  • If you have a Terminal session open, deactivate the virtual environment by running:
deactivate
  • Close the Terminal window. Your project folder stays intact for next time.

Delete - I don't want to use this again

Remove the entire project folder to free up disk space. This deletes your script, the virtual environment, and all installed packages.

  • If your virtual environment is active, deactivate it first by running:
deactivate
  • Delete the project folder by running:
rm -rf ~/Desktop/emotion-detector
  • Confirm the folder is gone by running:
ls ~/Desktop | grep emotion
  • You should see no output, confirming the folder has been removed.

Nice Work!

Nice Work!

You just built a text emotion detector from scratch using Python and machine learning. From raw text messages to real-time predictions, you took data through the entire ML pipeline.

You've learned how to:

  • Transform raw text into numerical features using TF-IDF vectorization, turning words into math that a model can learn from.
  • Train a Logistic Regression model on 16,000 real text messages to predict 6 emotions with high accuracy.
  • Build a reusable predict_emotion() function that analyzes any English sentence and returns confidence scores.
  • Compared multiple ML algorithms (Naive Bayes, Random Forest, Logistic Regression) to find the best emotion detector.

Ready to quiz yourself?