Predict Flower Species with Scikit-Learn
Train a K-Nearest Neighbors classifier to predict Iris flower species.
Introduction
30 Second Summary
Think about how you recognize a dog breed at the park. You look at its size, fur, and shape, then match it to breeds you have seen before.
In this project, you will train a machine learning model that examines flower measurements and predicts which species the flower belongs to. You will walk through the complete ML workflow that professionals use every day: load data, visualize it, train a model, and evaluate its performance.
What You'll Build
A classification model that uses petal and sepal measurements to predict Iris flower species using Python and scikit-learn.
By the end of this project, you'll have:
- A Jupyter Notebook containing your complete ML pipeline from data loading to model evaluation.
- Data visualizations showing how different flower species cluster by their measurements.
- A trained K-Nearest Neighbors classifier that predicts flower species on data it has never seen before.
- A confusion matrix and classification report proving your model's accuracy.
- A secret mission where you train a Decision Tree and compare its performance against your KNN model.
Are there any prerequisites?
You just need basic Python familiarity (variables, running code). No machine learning coding experience is needed. You should already have Python, pip, and Jupyter Notebook installed on your machine.
Set Up Your ML Toolkit
Building a machine learning model requires specialized tools beyond basic Python.
In this step, you will install four libraries for ML algorithms, data handling, and visualization. Then you will create a Jupyter Notebook where you will write and run all your code, one cell at a time.
In this step, get ready to:
- Install scikit-learn, pandas, matplotlib, and seaborn.
- Create a Jupyter Notebook called iris_classifier.
- Verify all library imports work by running your first cell.
Install the required libraries
You need four Python libraries for this project. Each one handles a different part of the ML workflow.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or Command Prompt (Windows) and press Enter to open it.
- Install all four libraries at once by running this command:
pip install scikit-learn==1.8.0 pandas==3.0.2 matplotlib==3.10.9 seaborn==0.13.2
What are these four libraries?
- scikit-learn provides ML algorithms and evaluation tools. This is the core of your ML toolkit.
- pandas handles data as clean, readable tables. Think spreadsheets in Python.
- matplotlib creates charts and visualizations from your data.
- seaborn builds on matplotlib to create prettier statistical visualizations with less code.
You should see Successfully installed messages for each library in your terminal output.
Seeing an error during installation?
- If you see pip: command not found, try replacing pip with pip3 in the command.
- If you see a Permission denied error on macOS or Linux, add --user to the end of the command.
- If the install hangs or times out, check your internet connection and try again.
Help me troubleshoot my pip install error.
Launch Jupyter and create a new notebook
Jupyter Notebook lets you write and run Python code in small chunks called cells. Each cell runs independently, so you get instant feedback as you build your ML pipeline.
- Launch Jupyter Notebook by running this command in the same terminal:
jupyter notebook
Your default browser opens to the Jupyter dashboard, showing a list of files and folders.
- Click New in the top-right corner of the Jupyter dashboard.
- Select Python 3 from the dropdown menu.
A new notebook opens in a separate browser tab with an empty code cell ready for input.
- Click on the notebook title at the top of the page (it says Untitled by default).
- Type iris_classifier and click Rename.
Your notebook title should now show iris_classifier at the top of the page.
Browser didn't open automatically?
- Check your terminal for a URL that looks like http://localhost:8888/?token=... and copy-paste it into your browser.
- If you see jupyter: command not found, Jupyter may not be installed. Run pip install notebook and try again.
Help me get Jupyter Notebook running in my browser.
Verify your imports
Before writing any ML code, you need to confirm that Python can find and load every library you just installed. One missing import will block everything later.
- Click inside the first empty cell in your iris_classifier notebook.
- Import all the libraries you will use throughout this project by typing this code into the cell:
# Cell 1: Import Libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, ConfusionMatrixDisplay
print("All libraries loaded successfully!")
What does this code do?
- pandas, matplotlib, and seaborn handle your data tables and visualizations.
- load_iris loads the built-in Iris flower dataset directly from scikit-learn. No file downloads needed.
- train_test_split splits your data into a training set and a testing set so your model is evaluated on data it has never seen.
- KNeighborsClassifier is the K-Nearest Neighbors algorithm you will train to classify flower species.
- accuracy_score, confusion_matrix, classification_report, and ConfusionMatrixDisplay are tools for measuring how well your model performs.
- Run the cell by pressing Shift+Enter.
You should see All libraries loaded successfully! printed directly below the cell with no error messages.
Seeing a ModuleNotFoundError?
- This means Jupyter is using a different Python installation than the one where you ran pip install. Close Jupyter, then reopen your terminal and run the pip install command again.
- Double-check that there are no typos in the import lines. Python import names are case-sensitive.
- If the error mentions a specific library (like sklearn), try installing just that one library from a new cell in Jupyter:
!pip install scikit-learn==1.8.0
Help me fix my ModuleNotFoundError in Jupyter Notebook.
Awesome, I've got everything!
Great. Double check you have saved your notebook before moving on.
I'd like to double check the full code
Here is the complete code you should have in Cell 1 of your iris_classifier notebook.
# Cell 1: Import Libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, ConfusionMatrixDisplay
print("All libraries loaded successfully!")
Your ML environment is ready. Next up, you will load the famous Iris flower dataset and explore what is inside it.
Load and Explore the Iris Dataset
Your libraries are installed and your notebook is ready. Now it's time to meet the data your model will learn from.
Every machine learning project starts with understanding the dataset. In this step, you'll load the Iris dataset, organize it into a readable table using pandas, and examine its statistics to understand what you're working with.
In this step, get ready to:
- Load the Iris dataset from scikit-learn and inspect its structure.
- Convert the raw data into a pandas DataFrame for easier viewing.
- Generate summary statistics to understand the range and balance of your features.
Load the dataset and inspect its structure
The Iris dataset is one of the most famous datasets in machine learning. It contains measurements from 150 flowers across three species, and it comes built into scikit-learn.
- Load the Iris dataset and print its structure by adding this code to a new cell in your notebook:
# Cell 2: Load the Dataset
iris = load_iris()
print("Feature names:", iris.feature_names)
print("Target names:", iris.target_names)
print("Dataset shape:", iris.data.shape)
What does this code do?
- load_iris() fetches the entire Iris dataset and stores it in a variable called iris.
- iris.feature_names lists the four measurements taken from each flower (sepal length, sepal width, petal length, petal width).
- iris.target_names lists the three species the model will learn to predict.
- iris.data.shape shows the dataset has 150 samples with 4 features each.
- Run the cell by pressing Shift+Enter.
- You should see four feature names, three target names (setosa, versicolor, virginica), and a dataset shape of (150, 4).
Seeing a NameError?
- Make sure you ran Cell 1 (your imports cell) before this cell. Jupyter cells must be executed in order.
- Check that load_iris is spelled exactly as shown, with an underscore between the two words.
- Help me fix a NameError when running load_iris() in my Jupyter Notebook.
Convert to a pandas DataFrame
Raw data stored in arrays is hard to read. A DataFrame organizes it into a clean table with labeled columns, making it much easier to explore.
- Create a DataFrame from the Iris data by adding this code to a new cell:
# Cell 3: Convert to DataFrame
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['species'] = iris.target
df['species_name'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
df.head(10)
What does this code do?
- pd.DataFrame(iris.data, columns=iris.feature_names) turns the raw number array into a table with descriptive column headers.
- df['species'] = iris.target adds a numeric species column where 0 is setosa, 1 is versicolor, and 2 is virginica.
- The .map() line creates a new column that translates those numbers into readable species names.
- df.head(10) displays the first 10 rows so you can preview the table.
- Run the cell by pressing Shift+Enter.
- You should see a table with 10 rows, where each row shows four measurement values plus the species number and species name.
Table not displaying?
- Make sure df.head(10) is the last line in the cell. Jupyter automatically displays the output of the last expression.
- If you see an error mentioning pd, confirm that Cell 1 ran successfully with import pandas as pd.
- Help me fix my DataFrame display issue in Jupyter Notebook.
Get summary statistics
Before training a model, you need to understand the range and distribution of your data. Summary statistics reveal the minimum, maximum, and average values for each feature.
- Generate summary statistics and check the class balance by adding this code to a new cell:
# Cell 4: Summary Statistics
print(df.describe())
print("\nSamples per species:")
print(df['species_name'].value_counts())
What does this code do?
- df.describe() calculates the count, mean, standard deviation, min, max, and quartile values for every numeric column.
- df['species_name'].value_counts() counts how many samples exist for each species.
- Run the cell by pressing Shift+Enter.
- You should see a statistics table showing ranges for all four features, followed by a count of 50 samples for each of the three species.
Why does balanced data matter?
Each species has exactly 50 samples. This is called a balanced dataset.
Balanced data means the model gets equal exposure to every class during training. If one species had 100 samples and another had 10, the model might become biased toward the majority class.
Seeing unexpected output?
- If describe() shows fewer columns than expected, make sure you created the DataFrame with all four feature columns in Cell 3.
- If value_counts() shows numbers instead of species names, check that you used df['species_name'] and not df['species'].
- Help me debug my summary statistics output in my Iris dataset notebook.
Awesome, I've got everything!
Great. Double check that you have saved your notebook by pressing Cmd+S (macOS) or Ctrl+S (Windows).
I'd like to double check the full code
Here is the complete code across all your cells so far. Make sure each cell in your notebook matches.
# Cell 1: Import Libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, ConfusionMatrixDisplay
print("All libraries loaded successfully!")
# Cell 2: Load the Dataset
iris = load_iris()
print("Feature names:", iris.feature_names)
print("Target names:", iris.target_names)
print("Dataset shape:", iris.data.shape)
# Cell 3: Convert to DataFrame
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['species'] = iris.target
df['species_name'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
df.head(10)
# Cell 4: Summary Statistics
print(df.describe())
print("\nSamples per species:")
print(df['species_name'].value_counts())
Your data is loaded, organized, and explored. Next up, you'll create visualizations that reveal how different flower species cluster by their measurements.
Visualize Your Data
You have your Iris dataset loaded into a pandas DataFrame and you know its basic statistics. Numbers in a table tell part of the story, but charts reveal something tables cannot: clusters, separations, and overlaps between species.
In this step, you will create visualizations that show how different flower species look when plotted by their measurements. These are the same patterns your ML model will learn to recognize.
In this step, get ready to:
- Create a scatter plot of petal measurements colored by species.
- Create a pairplot showing all feature combinations at once.
Create a scatter plot of petal measurements
A scatter plot puts each flower as a dot on a chart, with one measurement on each axis. Coloring dots by species lets you see whether species form distinct groups or blur together.
- Create a new cell in your notebook and add the following code to plot petal length vs. petal width, colored by species:
# Cell 5: Scatter Plot
plt.figure(figsize=(10, 6))
colors = ['red', 'green', 'blue']
for i, species in enumerate(iris.target_names):
subset = df[df['species'] == i]
plt.scatter(subset['petal length (cm)'], subset['petal width (cm)'],
c=colors[i], label=species, alpha=0.7)
plt.xlabel('Petal Length (cm)')
plt.ylabel('Petal Width (cm)')
plt.title('Iris Species by Petal Measurements')
plt.legend()
plt.show()
What does this code do?
- plt.figure(figsize=(10, 6)) creates a chart that is 10 inches wide and 6 inches tall.
- The for loop goes through each species one at a time. It filters the DataFrame to only that species, then plots its petal length and petal width as colored dots.
- alpha=0.7 makes dots slightly transparent so overlapping points are easier to see.
- plt.legend() adds a color key so you know which color represents which species.
- Run the cell by pressing Shift+Enter.
- You should see a scatter plot with three colored clusters of dots: red for setosa, green for versicolor, and blue for virginica.
Notice how the red setosa dots cluster in the bottom-left, clearly separated from the other two species. Versicolor and virginica overlap a bit. This overlap is what makes classification interesting.
Why does this matter for ML?
When species form distinct clusters in a chart, it means their measurements are different enough for a model to tell them apart. The clear separation of setosa means the model will predict it easily. The overlap between versicolor and virginica is where mistakes are most likely to happen.
Don't see a chart?
- Make sure you ran Cells 1 through 4 first. This cell depends on df and iris existing from earlier cells.
- Check for a NameError in the output. If you see one, restart your kernel by clicking Kernel then Restart & Run All.
- Make sure the column names in your code match exactly: petal length (cm) and petal width (cm) include spaces and parentheses.
- Help me debug my scatter plot code.
Create a pairplot to see all feature combinations
Your scatter plot showed one combination of features. The Iris dataset has four features, which means there are many possible combinations to check. Seaborn's pairplot shows every feature plotted against every other feature in a single grid.
- Create a new cell and add the following code to generate the pairplot:
# Cell 6: Pairplot
sns.pairplot(df, hue='species_name', vars=iris.feature_names)
plt.show()
What does this code do?
- sns.pairplot() takes your DataFrame and creates a grid of scatter plots. Each row and column represents a different feature.
- hue='species_name' colors the dots by species so you can see how each species clusters across every feature pair.
- The diagonal of the grid shows distribution histograms for each feature, so you can see how measurements are spread within each species.
- Run the cell by pressing Shift+Enter.
- You should see a 4x4 grid of charts. Each off-diagonal cell is a scatter plot of two features, and each diagonal cell is a histogram.
Look at the grid and notice which plots show the clearest separation between species. The petal length and petal width combination stands out as the strongest separator. Your ML model will discover this automatically during training.
Extra for Experts: Why are petal features stronger separators?
Sepal measurements (length and width) overlap heavily across all three species. Petal measurements vary much more between species. This means petal features carry more "signal" for telling species apart. When you train your model, features with stronger separation contribute more to accurate predictions.
Pairplot taking a long time or not displaying?
- Pairplots generate many charts at once, so they can take a few seconds. Wait at least 10 seconds before assuming something is wrong.
- If you see an error about species_name not being found, make sure you ran Cell 3 where you created the species_name column in your DataFrame.
- Help me troubleshoot my pairplot.
Awesome, I've got everything!
Great. Double check you have both charts displaying in your notebook before moving on.
I'd like to double check the full code
Here is the complete code for your notebook so far, covering Cells 1 through 6.
# Cell 1: Import Libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, ConfusionMatrixDisplay
print("All libraries loaded successfully!")
# Cell 2: Load the Dataset
iris = load_iris()
print("Feature names:", iris.feature_names)
print("Target names:", iris.target_names)
print("Dataset shape:", iris.data.shape)
# Cell 3: Convert to DataFrame
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['species'] = iris.target
df['species_name'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
df.head(10)
# Cell 4: Summary Statistics
print(df.describe())
print("\nSamples per species:")
print(df['species_name'].value_counts())
# Cell 5: Scatter Plot
plt.figure(figsize=(10, 6))
colors = ['red', 'green', 'blue']
for i, species in enumerate(iris.target_names):
subset = df[df['species'] == i]
plt.scatter(subset['petal length (cm)'], subset['petal width (cm)'],
c=colors[i], label=species, alpha=0.7)
plt.xlabel('Petal Length (cm)')
plt.ylabel('Petal Width (cm)')
plt.title('Iris Species by Petal Measurements')
plt.legend()
plt.show()
# Cell 6: Pairplot
sns.pairplot(df, hue='species_name', vars=iris.feature_names)
plt.show()
Your visualizations reveal a clear story: some species are easy to separate, and some features are better at separating them than others. Next up, you will split your data and train a model that learns these patterns automatically.
Split Data and Train Your Model
Your visualizations revealed clear patterns in the Iris data. Setosa clusters away from the pack, while versicolor and virginica overlap slightly.
Now it is time to build a model that learns those patterns automatically. You will split your data, train a K-Nearest Neighbors classifier, and make predictions on data the model has never seen.
In this step, get ready to:
- Split your dataset into training and testing sets.
- Train a K-Nearest Neighbors classifier on the training data.
- Use your trained model to predict flower species on unseen test data.
Split the data into training and testing sets
Training a model on all your data and then testing it on the same data is like grading your own homework. You need to hold some data back so you can test the model on samples it has never seen.
What is a train/test split?
A train/test split divides your dataset into two groups. The training set is what the model learns from. The testing set is what you use afterwards to measure how well the model performs on new data.
- In a new cell in your notebook, separate the features from the target and split the data by running this code:
# Separate features (measurements) from target (species labels)
X = iris.data
y = iris.target
# Split into 80% training, 20% testing
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"Training samples: {X_train.shape[0]}")
print(f"Testing samples: {X_test.shape[0]}")
What does this code do?
- X holds the four flower measurements (features) and y holds the species labels (the target you want to predict).
- train_test_split randomly shuffles the data and puts 80% into training and 20% into testing.
- random_state=42 locks the random shuffle so everyone gets the same split. This makes your results reproducible.
- Run the cell by pressing Shift+Enter.
- You should see Training samples: 120 and Testing samples: 30 printed below the cell.
Seeing a NameError?
- If you see NameError: name 'iris' is not defined, go back and run Cell 1 (imports) and Cell 2 (load dataset) first. Jupyter requires cells to run in order.
- If you see NameError: name 'train_test_split' is not defined, re-run Cell 1 where you imported all the libraries.
- Help me debug my train/test split cell
Create and train the KNN classifier
KNN is one of the most intuitive ML algorithms. When it needs to classify a new flower, it finds the closest flowers in the training data and goes with the majority vote.
- In a new cell, create and train your KNN model by running this code:
# Create a KNN model that checks the 3 nearest neighbors
model = KNeighborsClassifier(n_neighbors=3)
# Train the model on the training data
model.fit(X_train, y_train)
print("Model trained!")
What does this code do?
- KNeighborsClassifier(n_neighbors=3) creates a model that looks at the 3 closest training samples to make each prediction.
- model.fit(X_train, y_train) is where the model learns the patterns in your training data. Two lines of code to train an ML model.
- Run the cell by pressing Shift+Enter.
- You should see Model trained! printed below the cell.
Not seeing 'Model trained!'?
- Make sure you ran the previous cell that creates X_train and y_train. The model needs training data to learn from.
- Check that you typed KNeighborsClassifier with a capital K, N, and C. Python class names are case-sensitive.
- Help me debug my KNN training cell
Why 3 neighbors?
The n_neighbors=3 parameter tells the model to check the 3 closest flowers in the training set when classifying a new one. An odd number avoids ties in the majority vote. 3 is a solid starting point for a small dataset like Iris.
Make predictions on the test set
Your model has learned from 120 training samples. Now you will hand it the 30 test samples it has never seen and ask it to predict each flower's species.
- In a new cell, generate predictions on the test data by running this code:
# Use the trained model to predict species for test samples
y_pred = model.predict(X_test)
print("Predictions:", y_pred)
print("Actual: ", y_test)
What does this code do?
- model.predict(X_test) feeds the 30 test flower measurements into your trained model and returns a predicted species label (0, 1, or 2) for each one.
- The output prints both rows so you can visually compare predictions against the actual labels. Every number that matches is a correct prediction.
- Run the cell by pressing Shift+Enter.
- You should see two rows of numbers. The Predictions row shows what your model guessed. The Actual row shows the correct answers.
Seeing a NameError for model or X_test?
- If model is not defined, go back and run the cell where you created and trained the KNN classifier.
- If X_test is not defined, go back and run the cell where you called train_test_split.
- Help me debug my prediction cell
Counting matches by hand is tedious. That is what evaluation metrics are for.
Awesome, I've got everything!
Double check that you have saved your notebook with all cells up to and including the predictions cell.
I'd like to double check the full code
Here is the complete notebook code through the end of this step. Each comment marks the start of a separate Jupyter cell.
# Cell 1: Import Libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, ConfusionMatrixDisplay
print("All libraries loaded successfully!")
# Cell 2: Load the Dataset
iris = load_iris()
print("Feature names:", iris.feature_names)
print("Target names:", iris.target_names)
print("Dataset shape:", iris.data.shape)
# Cell 3: Convert to DataFrame
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['species'] = iris.target
df['species_name'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
df.head(10)
# Cell 4: Summary Statistics
print(df.describe())
print("\nSamples per species:")
print(df['species_name'].value_counts())
# Cell 5: Scatter Plot
plt.figure(figsize=(10, 6))
colors = ['red', 'green', 'blue']
for i, species in enumerate(iris.target_names):
subset = df[df['species'] == i]
plt.scatter(subset['petal length (cm)'], subset['petal width (cm)'],
c=colors[i], label=species, alpha=0.7)
plt.xlabel('Petal Length (cm)')
plt.ylabel('Petal Width (cm)')
plt.title('Iris Species by Petal Measurements')
plt.legend()
plt.show()
# Cell 6: Pairplot
sns.pairplot(df, hue='species_name', vars=iris.feature_names)
plt.show()
# Cell 7: Split the Data
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"Training samples: {X_train.shape[0]}")
print(f"Testing samples: {X_test.shape[0]}")
# Cell 8: Train the Model
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
print("Model trained!")
# Cell 9: Make Predictions
y_pred = model.predict(X_test)
print("Predictions:", y_pred)
print("Actual: ", y_test)
Your model is trained and making predictions. Next up, you will measure exactly how well it performs using accuracy scores, a confusion matrix, and a full classification report.
Evaluate Your Model's Performance
In the previous step, you trained your KNN model and compared its predictions against the actual species labels.
Eyeballing two rows of numbers does not scale. In this step, you will use three standard evaluation tools that data scientists rely on to measure how well a model performs.
In this step, get ready to:
- Calculate your model's accuracy score.
- Visualize a confusion matrix that shows exactly where the model gets predictions right and wrong.
- Generate a classification report and predict the species of a brand new flower.
Calculate the accuracy score
Accuracy is the simplest evaluation metric in machine learning. It tells you what percentage of your model's predictions were correct.
- In a new cell in your notebook, calculate and print the accuracy by running this code:
# Cell 10: Accuracy Score
accuracy = accuracy_score(y_test, y_pred)
print(f"Model Accuracy: {accuracy * 100:.2f}%")
What does this code do?
- accuracy_score(y_test, y_pred) compares every predicted label in y_pred against the true label in y_test and returns the fraction that match.
- Multiplying by 100 converts the fraction (e.g. 1.0) into a readable percentage (e.g. 100.00%).
- Run the cell by pressing Shift+Enter.
- You should see output like Model Accuracy: 100.00%.
Why is the accuracy so high?
The Iris dataset is clean, balanced, and well-separated. That makes it perfect for learning the ML workflow without getting bogged down by messy data. Real-world datasets are rarely this clean.
Seeing a NameError?
- If you see NameError: name 'y_test' is not defined, go back and run every cell above this one in order. Jupyter cells must be run sequentially for variables to be available.
- If you see NameError: name 'accuracy_score' is not defined, make sure Cell 1 (your imports cell) has been run successfully.
- Still stuck? Help me debug a NameError in my Jupyter Notebook when calculating accuracy score.
Visualize the confusion matrix
Accuracy tells you the overall score, but not where the model struggles. A confusion matrix breaks down predictions species by species so you can see exactly which classes get mixed up.
- In a new cell, generate and display the confusion matrix by running this code:
# Cell 11: Confusion Matrix
ConfusionMatrixDisplay.from_estimator(
model, X_test, y_test,
display_labels=iris.target_names,
cmap=plt.cm.Blues
)
plt.title('Confusion Matrix')
plt.show()
How do I read a confusion matrix?
- Each row represents the actual species. Each column represents the predicted species.
- Numbers on the diagonal (top-left to bottom-right) are correct predictions. The bigger these numbers, the better.
- Numbers off the diagonal are mistakes. For example, a number in the setosa row and versicolor column means the model predicted versicolor when the flower was actually setosa.
- Run the cell by pressing Shift+Enter.
- You should see a blue heatmap grid with species names along both axes. The diagonal cells should hold all the counts, and the off-diagonal cells should show 0.
Don't see the chart?
- Make sure Cell 1 (imports) was run successfully. ConfusionMatrixDisplay and plt both come from that first import cell.
- If the chart appears but looks empty, confirm you ran Cell 8 (training the model) before this cell. The from_estimator method needs a trained model.
- Still stuck? Help me fix my confusion matrix visualization in Jupyter.
Generate a classification report and test with new data
A classification report goes deeper than accuracy. It gives you three metrics for each species: precision, recall, and F1-score.
- In a new cell, print the full classification report by running this code:
# Cell 12: Classification Report
print(classification_report(y_test, y_pred, target_names=iris.target_names))
What do precision, recall, and F1-score mean?
- Precision answers: "Of all the flowers the model labeled as setosa, how many were actually setosa?"
- Recall answers: "Of all the actual setosa flowers, how many did the model find?"
- F1-score is the balance between precision and recall. A perfect score is 1.00.
- Run the cell. You should see a table with precision, recall, and f1-score columns, with one row per species and a summary row at the bottom.
Now for the fun part. Your model has only seen flowers from the test set. Let's hand it a completely new flower measurement and see what it predicts.
- In a new cell, test your model on a brand new flower by running this code:
# Cell 13: Predict New Flowers
new_flower = [[5.1, 3.5, 1.4, 0.2]]
prediction = model.predict(new_flower)
print(f"New flower prediction: {iris.target_names[prediction[0]]}")
What does this code do?
- new_flower holds four measurements in the same order the model expects: sepal length, sepal width, petal length, petal width.
- model.predict() finds the 3 nearest neighbors in the training data and returns the majority species.
- The double brackets [[...]] are needed because predict() expects a 2D array (a list of samples), even when you only have one sample.
- Run the cell. You should see New flower prediction: setosa printed below the cell.
Your model just classified a flower it has never seen before. That is machine learning in action.
Seeing a ValueError about input shape?
- Make sure new_flower uses double brackets: [[5.1, 3.5, 1.4, 0.2]]. Single brackets give a 1D array, and the model needs a 2D array.
- Confirm you have exactly 4 values inside the inner brackets. The model was trained on 4 features, so it expects 4 measurements per flower.
- Still stuck? Help me fix a ValueError when predicting with my KNN model.
Pro tip: try your own measurements
Change the four numbers in new_flower and run the cell again. Try [[6.5, 3.0, 5.5, 2.0]] for a flower that should land in the virginica range. Experimenting with different values builds intuition for how the model draws its boundaries.
Awesome, I've got everything!
Double check that you have saved your notebook before moving on.
I'd like to double check the full code
Here is the complete notebook code across all cells. Compare it against your cells to make sure nothing is missing.
# Cell 1: Import Libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, ConfusionMatrixDisplay
print("All libraries loaded successfully!")
# Cell 2: Load the Dataset
iris = load_iris()
print("Feature names:", iris.feature_names)
print("Target names:", iris.target_names)
print("Dataset shape:", iris.data.shape)
# Cell 3: Convert to DataFrame
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['species'] = iris.target
df['species_name'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
df.head(10)
# Cell 4: Summary Statistics
print(df.describe())
print("\nSamples per species:")
print(df['species_name'].value_counts())
# Cell 5: Scatter Plot
plt.figure(figsize=(10, 6))
colors = ['red', 'green', 'blue']
for i, species in enumerate(iris.target_names):
subset = df[df['species'] == i]
plt.scatter(subset['petal length (cm)'], subset['petal width (cm)'],
c=colors[i], label=species, alpha=0.7)
plt.xlabel('Petal Length (cm)')
plt.ylabel('Petal Width (cm)')
plt.title('Iris Species by Petal Measurements')
plt.legend()
plt.show()
# Cell 6: Pairplot
sns.pairplot(df, hue='species_name', vars=iris.feature_names)
plt.show()
# Cell 7: Split the Data
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"Training samples: {X_train.shape[0]}")
print(f"Testing samples: {X_test.shape[0]}")
# Cell 8: Train the Model
model = KNeighborsClassifier(n_neighbors=3)
model.fit(X_train, y_train)
print("Model trained!")
# Cell 9: Make Predictions
y_pred = model.predict(X_test)
print("Predictions:", y_pred)
print("Actual: ", y_test)
# Cell 10: Accuracy Score
accuracy = accuracy_score(y_test, y_pred)
print(f"Model Accuracy: {accuracy * 100:.2f}%")
# Cell 11: Confusion Matrix
ConfusionMatrixDisplay.from_estimator(
model, X_test, y_test,
display_labels=iris.target_names,
cmap=plt.cm.Blues
)
plt.title('Confusion Matrix')
plt.show()
# Cell 12: Classification Report
print(classification_report(y_test, y_pred, target_names=iris.target_names))
# Cell 13: Predict New Flowers
new_flower = [[5.1, 3.5, 1.4, 0.2]]
prediction = model.predict(new_flower)
print(f"New flower prediction: {iris.target_names[prediction[0]]}")
Secret mission
Compare KNN with a Decision Tree
You have trained one model, but real data scientists always try multiple algorithms before picking a winner. Train a Decision Tree classifier, visualize how it makes decisions, and compare its performance against your KNN model.
Before you go
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally, so there are no ongoing costs.
Resources you used:
- Jupyter Notebook file (iris_classifier).
- Running Jupyter Notebook server process.
- Installed Python libraries: scikit-learn, pandas, matplotlib, seaborn.
Keep everything running
No action needed. Choose this if you are still actively building or want to experiment more with your model.
- Your Jupyter Notebook server stays running in the terminal where you launched it.
- Your notebook file and all installed libraries remain available.
Pause - I'll come back to this later
Shut down the Jupyter Notebook server to free up memory. Your notebook file and installed libraries stay on your machine for next time.
- Go to the terminal where Jupyter is running and press Ctrl + C to stop the server.
- Confirm the shutdown when prompted.
- To resume later, open a terminal and run jupyter notebook again from the same directory.
Delete - I don't want to use this again
Remove all project resources and start fresh.
- Stop the Jupyter Notebook server by pressing Ctrl + C in the terminal.
- Delete your notebook file (iris_classifier.ipynb) from your file system.
- To uninstall the Python libraries, run:
pip uninstall scikit-learn pandas matplotlib seaborn -y
Mission accomplished
You Just Trained Your First ML Model
Nice work! You just built a complete machine learning pipeline that takes raw flower measurements and predicts species with high accuracy. That is the exact workflow data scientists use every day.
Here's what you learned:
- Loaded and explored the Iris dataset with pandas, then created scatter plots and pairplots to visualize how species cluster by their measurements.
- Split data into training and testing sets, trained a K-Nearest Neighbors classifier, and used it to predict flower species on data the model had never seen.
- Evaluated your model using accuracy score, a confusion matrix, and a classification report to measure exactly how well it performs.
- Trained a Decision Tree classifier, visualized its decision logic, and compared its performance against your KNN model.
Ready to quiz yourself?