Classify Iris Flowers with Python

Build a Colab notebook that classifies Iris flowers with a decision tree.

Introduction

30 Second Summary

Rows of flower measurements can look like ordinary numbers. Hidden patterns inside them can separate one species from another.

In this project, you will build an interactive flower-identification notebook in Google Colab. The notebook takes you from raw Iris measurements to an honestly tested species prediction.

What You'll Build

You will enter four measurements for a new flower and see your trained model print its predicted Iris species.

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

  • A labeled DataFrame containing 150 Iris flowers. Summary statistics will make the range of each measurement visible.
  • A color-coded scatter plot that reveals species patterns in petal measurements. A visible 33.33% baseline will expose the limits of always guessing the first species.
  • An honestly evaluated decision tree classifier tested on unseen flower records. A new-flower prediction will print a human-readable species name.
  • Secret Mission: Compare shallow and deeper decision trees using training accuracy and testing accuracy to spot the first signs of overfitting.

Are there any prerequisites?

No programming experience is required. A Google account gives you access to the free Google Colab workspace used throughout the project.

Before We Start

Before any hands-on work, take a moment to commit to building an Iris flower classifier. Connecting that goal to your reason for learning the data science workflow gives every later step a purpose.

Set Up Your Colab Lab

The flower classifier needs a place to run Python. Local software setup would delay your first data result.

Google Colab provides a browser-based notebook with no local installation. It stores your notebook in Google Drive.

In this step, get ready to:
  • Create a blank Google Colab notebook.
  • Rename the notebook for your Iris flower classifier.
  • Run the setup cell to load the data science tools.
Create your Colab notebook

A Colab notebook combines code cells with their outputs. Each cell runs in a temporary runtime managed by Colab.

  • Open Google Colab in your browser.
  • Sign in to Colab with the Google account you confirmed earlier.
  • Click New notebook on the Colab landing page.
  • Confirm that the notebook page shows one empty code cell.

Good start. Your blank notebook is now a browser-based lab stored in Google Drive.

Name the notebook

A clear notebook name makes the project easy to find later. It also gives the saved file a purpose you can recognise at a glance.

  • Click the current notebook title in the top-left corner.
  • Replace the current title with iris_flower_classifier.ipynb.
  • Press Enter to apply the new name.
  • Confirm that the title at the top of the notebook reads iris_flower_classifier.ipynb.

Your flower lab now has a clear home in Google Drive.

Load the data science tools

Pandas handles tables. Matplotlib handles charts.

The scikit-learn library supplies the dataset tools. It also supplies the classifier and evaluation tools.

  • Place the required imports in the first code cell by copying this code:
# Cell 1: Setup
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

print("Data science tools loaded.")

What does this code do?

  • The pd alias gives the notebook a short name for working with DataFrames.
  • The plt alias provides the plotting tools used for the flower chart.
  • The load_iris function loads the built-in Iris dataset.
  • The accuracy_score function measures the fraction of correct predictions.
  • The train_test_split function separates training records from testing records.
  • The DecisionTreeClassifier class provides the model used later in the project.

Before you run the cell, do you expect every library to load successfully?

  • Run the setup cell by clicking the play button beside it.

You'll see Data science tools loaded. beneath the cell. No import error should appear.

  • Wait for Colab to finish saving the notebook to Google Drive.
  • Confirm that the notebook title still reads iris_flower_classifier.ipynb.

That is your setup complete. The active Colab runtime now has every project tool ready to use.

Seeing an import error?

  • Compare every import line with the setup cell above to catch a missing character.
  • Use Colab's runtime status area to reconnect if the temporary runtime disconnected.
  • Run the setup cell again after correcting the problem.

Help me fix my Colab import error.

✔️ Awesome, I've got everything!

Everything matches. Your notebook is ready for the Iris dataset.

ⓧ I'd like to double check the full code

# Cell 1: Setup
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

print("Data science tools loaded.")

Your Colab lab is ready. Next up, you'll load the Iris dataset to see what each flower record contains.

Explore the Iris Dataset

Your Google Colab lab has loaded the tools from the previous step. The next goal is to turn those tools toward real flower records.

A classifier cannot be trusted until you know what each row represents. You will inspect the Iris dataset before any model sees it.

In this step, get ready to:
  • Load the built-in Iris dataset into a DataFrame.
  • Separate the measurement features from the target labels.
  • Inspect the dataset through several printed views.
Load and separate the Iris data

The Iris dataset contains measurements from 150 flowers. Each row combines four measurements with one numbered species label.

  • Add a new Python cell directly below the setup cell in iris_flower_classifier.ipynb.
  • Load the data into separate notebook variables by pasting this code into the new cell:
# Cell 2: Load and explore the data
iris = load_iris(as_frame=True)
data = iris.frame.copy()
X = iris.data
y = iris.target

print(f"Rows and columns: {data.shape}")

What does this code do?

  • The load_iris(as_frame=True) call loads the built-in dataset with table-based data structures.
  • The iris.frame.copy() call creates a separate copy of the complete table.
  • The X variable stores the four measurement columns.
  • The y variable stores the numbered species labels.
  • The final line prints the dimensions of the complete table.
  • Run the new cell by clicking the triangular icon beside it.
  • Confirm the output reads Rows and columns: (150, 5).

Good start. Your runtime now holds all 150 flower records in the variables that the rest of the notebook uses.

Dataset cell not running?

  • Rerun the setup cell if Colab reports that load_iris is unavailable.
  • Check that as_frame=True includes the underscore and capitalized value.
  • Run the dataset cell again after correcting the affected line.

Help me fix the dataset cell.

Explore the rows and statistics

The table shape tells you how much data exists. Sample rows plus descriptive statistics reveal what the measurement columns contain.

  • Find print(f"Rows and columns: {data.shape}") at the bottom of the second cell.
  • Add the remaining exploration output by pasting this code directly below that line:
print("\nFirst five rows:")
print(data.head())
print("\nDescriptive statistics:")
print(data.describe())
print(f"\nTarget names: {list(iris.target_names)}")

What does this code reveal?

  • The head() method returns the first five flower records.
  • The describe() method summarizes every numeric column.
  • The iris.target_names value translates the numbered labels into species names.
  • The newline characters separate the printed sections for easier reading.

Before you run the completed cell, which printed section do you expect will reveal the most about the flower measurements?

  • Run the completed cell by clicking the triangular icon beside it.
  • Scroll through the output to inspect every printed section.

You will see Rows and columns: (150, 5) above five sample rows.

Below the sample rows, you will see a descriptive-statistics table. The final line lists setosa, versicolor, and virginica.

Missing part of the output?

  • Check that the new print lines sit inside the same cell as the dataset-loading code.
  • Check that every opening parenthesis has a matching closing parenthesis.
  • Run the completed cell from the beginning after fixing the code.

Help me restore the missing output.

✔️ Awesome, I've got everything!

Your completed exploration cell now loads the Iris data and prints every required view.

ⓧ I'd like to double check the full code

# Cell 1: Setup
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

print("Data science tools loaded.")

# Cell 2: Load and explore the data
iris = load_iris(as_frame=True)
data = iris.frame.copy()
X = iris.data
y = iris.target

print(f"Rows and columns: {data.shape}")
print("\nFirst five rows:")
print(data.head())
print("\nDescriptive statistics:")
print(data.describe())
print(f"\nTarget names: {list(iris.target_names)}")

That is your first real dataset check complete. Next, you will turn two of these measurements into a species-colored chart.

Visualize Patterns and Set a Baseline

Your Iris DataFrame in Google Colab now turns 150 flower records into a table you can inspect. The summary statistics show the range of each measurement.

A scatter plot can reveal species patterns hidden in those columns. You will then test an always-first-species baseline to give later models a comparison point.

In this step, get ready to:
  • Plot two petal measurements using species-based colors.
  • Measure the accuracy of a one-species guessing rule.
Plot petal measurements by species

A feature is a measured property of each flower. The target labels supply the species grouping for the chart.

You will use Matplotlib to place the third feature on one axis. The fourth feature goes on the other axis.

  • Create a code cell directly beneath the exploration cell.
  • Copy the plotting code below into the new cell.
# Cell 3: Visualize two useful features
fig, ax = plt.subplots()
ax.scatter(
    X[iris.feature_names[2]],
    X[iris.feature_names[3]],
    c=y,
)
ax.set_xlabel(iris.feature_names[2])
ax.set_ylabel(iris.feature_names[3])
ax.set_title("Iris petal measurements by species")
plt.show()

print(f"Color order: {list(enumerate(iris.target_names))}")

What Does This Code Do?

  • The fig variable holds the overall Matplotlib figure. The ax variable provides the plotting area.
  • The third and fourth feature names select two petal measurements.
  • The c=y argument uses each target label to choose a point color.
  • The final printout links each numeric color value to a species name.
  • Run the new plotting cell with the run control to its left.

You should see a species-colored scatter plot titled Iris petal measurements by species. Below it, you should see Color order: followed by the three species from your earlier output.

That is your first visual result: the notebook now exposes species structure that the table hid.

  • Save iris_flower_classifier.ipynb after the chart appears.

Plot Missing or Blank?

  • Rerun the exploration cell if the runtime no longer contains X, y, or iris.
  • Check that the two feature references are X[iris.feature_names[2]] and X[iris.feature_names[3]].

Help me debug my Iris scatter plot.

Test the always-zero baseline

A baseline is a simple reference strategy. This version converts every target label to zero, which makes every prediction the first species.

The accuracy_score(y, baseline_predictions) call calculates the fraction of correct guesses. The result shows how far a fixed guessing rule gets without learning from the features.

  • Create another code cell directly beneath the plotting cell.
  • Copy the baseline code below into the new cell.
# Cell 4: Establish a simple baseline
baseline_predictions = y * 0
baseline_accuracy = accuracy_score(y, baseline_predictions)
print(f"Baseline accuracy: {baseline_accuracy:.2%}")

What Does This Code Do?

  • The baseline_predictions variable contains zero for every flower.
  • The baseline_accuracy variable stores the fraction of labels that match those zero predictions.
  • The :.2% format displays that fraction as a percentage with two decimal places.

Before you run this cell, consider this question: what fraction of the flowers will the one-species rule classify correctly.

  • Run the baseline cell with the run control to its left.

You should see Baseline accuracy: 33.33%. The three Iris species each contain 50 of the 150 flowers.

This shortfall is intentional. The guessing rule recognizes none of the structure visible in your scatter plot.

That is a strong checkpoint: your notebook now has a clear score for every trained model to beat.

  • Save iris_flower_classifier.ipynb after the baseline result appears.

Baseline Result Missing or Different?

  • Rerun the earlier notebook cells if the runtime has lost y.
  • Check that baseline_predictions = y * 0 still uses zero.
  • Check that the score compares y with baseline_predictions.

Help me debug my baseline accuracy result.

The cumulative notebook should now match the version below.

✔️ Awesome, I've got everything!

Your plotting and baseline cells are in place. The notebook is ready for the next step.

ⓧ I'd like to double check the full code

  • Compare your notebook cells with the complete cumulative code below.
# Cell 1: Setup
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

print("Data science tools loaded.")

# Cell 2: Load and explore the data
iris = load_iris(as_frame=True)
data = iris.frame.copy()
X = iris.data
y = iris.target

print(f"Rows and columns: {data.shape}")
print("\nFirst five rows:")
print(data.head())
print("\nDescriptive statistics:")
print(data.describe())
print(f"\nTarget names: {list(iris.target_names)}")

# Cell 3: Visualize two useful features
fig, ax = plt.subplots()
ax.scatter(
    X[iris.feature_names[2]],
    X[iris.feature_names[3]],
    c=y,
)
ax.set_xlabel(iris.feature_names[2])
ax.set_ylabel(iris.feature_names[3])
ax.set_title("Iris petal measurements by species")
plt.show()

print(f"Color order: {list(enumerate(iris.target_names))}")

# Cell 4: Establish a simple baseline
baseline_predictions = y * 0
baseline_accuracy = accuracy_score(y, baseline_predictions)
print(f"Baseline accuracy: {baseline_accuracy:.2%}")

You now have visible species patterns plus a baseline score. Next, you will discover whether a trained classifier can beat that score on unseen flowers.

Train and Test Your Classifier

Your Google Colab notebook has already exposed the limit of a fixed guess. The 33.33% baseline cannot learn from the flower measurements.

A train/test split keeps some flowers out of training so they can provide an honest evaluation. A decision tree can then learn patterns from the training rows before facing those unseen flowers.

In this step, get ready to:
  • Create a reproducible 80/20 split that preserves all three species.
  • Train a depth-limited decision tree using only the training rows.
  • Measure accuracy on unseen flowers and compare actual species with predictions.
Train and score on separate data

The test rows act like flowers the classifier encounters after training. Scoring those held-back rows shows whether the learned pattern works beyond the examples used to build it.

  • Use the add-cell control beneath the baseline cell to create a code cell.
  • Paste the following training pipeline into that cell:
# Cell 5: Train and evaluate on separate data
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y,
)

model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
test_predictions = model.predict(X_test)
test_accuracy = accuracy_score(y_test, test_predictions)

print(f"Test accuracy: {test_accuracy:.2%}")

What does this code do?

  • The train_test_split call reserves 20% of the flowers for testing.
  • The stratify=y setting preserves the species balance across both subsets.
  • The random_state=42 setting gives the split reproducibility across repeated runs.
  • The max_depth=3 setting limits how many levels of decisions the tree can learn.
  • The model.fit call trains the tree using only X_train and y_train.
  • The model.predict call produces a species prediction for every row in X_test.
  • The test_accuracy value measures the fraction of those unseen flowers classified correctly.
  • Run the cell with its play button.
  • Wait for iris_flower_classifier.ipynb to finish saving to Google Drive.

You will see Test accuracy: followed by a percentage. The completed cell confirms that the split variables and fitted model now exist in the runtime.

That first learned score is in place. Your decision tree is now being judged on flowers it did not see during training.

Does the training cell stop with an error?

Rerun the earlier notebook cells in order if Colab reports that X, y, or an imported tool is missing. A restarted runtime forgets variables created by previous cells.

Check that model.fit uses X_train and y_train if the model cannot make test predictions.

Help me fix my missing split or prediction variables.

Add the actual-versus-predicted table

A single percentage summarizes the overall result. A row-by-row comparison reveals which species the classifier predicted for individual test flowers.

  • Find this line at the bottom of the training cell: print(f"Test accuracy: {test_accuracy:.2%}").
  • Replace that line with the following block:
comparison = pd.DataFrame(
    {
        "actual": iris.target_names[y_test],
        "predicted": iris.target_names[test_predictions],
    }
)

print(f"Test accuracy: {test_accuracy:.2%}")
print(comparison.head(10))

How does the comparison work?

  • The comparison DataFrame translates numeric class labels into species names through iris.target_names.
  • The actual column contains the correct species for each held-back flower.
  • The predicted column contains the classifier's answer for the same flower.
  • The head(10) call keeps the displayed comparison focused on ten test rows.
  • Decide whether you expect the test accuracy to beat the 33.33% baseline.
  • Run the completed training cell with its play button.
  • Wait for iris_flower_classifier.ipynb to finish saving to Google Drive.

You will see a test accuracy percentage. Below it, you will see ten rows with actual and predicted species columns.

You have crossed the key evaluation gap. Your classifier now proves itself on flowers it did not see during training.

Missing the comparison table?

Make sure the comparison block appears before both print lines in the same cell. Python must create the DataFrame before it can display the first ten rows.

Rerun the earlier cells in order if Colab reports that a split or prediction variable is missing.

Help me debug my actual-versus-predicted table.

✔️ Awesome, I've got everything!

Your notebook is saved with the reproducible split, trained decision tree, test score, and ten-row comparison table.

ⓧ I'd like to double check the full code

# Cell 1: Setup
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

print("Data science tools loaded.")

# Cell 2: Load and explore the data
iris = load_iris(as_frame=True)
data = iris.frame.copy()
X = iris.data
y = iris.target

print(f"Rows and columns: {data.shape}")
print("\nFirst five rows:")
print(data.head())
print("\nDescriptive statistics:")
print(data.describe())
print(f"\nTarget names: {list(iris.target_names)}")

# Cell 3: Visualize two useful features
fig, ax = plt.subplots()
ax.scatter(
    X[iris.feature_names[2]],
    X[iris.feature_names[3]],
    c=y,
)
ax.set_xlabel(iris.feature_names[2])
ax.set_ylabel(iris.feature_names[3])
ax.set_title("Iris petal measurements by species")
plt.show()

print(f"Color order: {list(enumerate(iris.target_names))}")

# Cell 4: Establish a simple baseline
baseline_predictions = y * 0
baseline_accuracy = accuracy_score(y, baseline_predictions)
print(f"Baseline accuracy: {baseline_accuracy:.2%}")

# Cell 5: Train and evaluate on separate data
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y,
)

model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
test_predictions = model.predict(X_test)
test_accuracy = accuracy_score(y_test, test_predictions)

comparison = pd.DataFrame(
    {
        "actual": iris.target_names[y_test],
        "predicted": iris.target_names[test_predictions],
    }
)

print(f"Test accuracy: {test_accuracy:.2%}")
print(comparison.head(10))

Your decision tree can now classify unseen test flowers with a measurable result. Next up, you will give it one fresh flower and translate its prediction into a species name.

Classify a New Flower

Your decision tree has already proved itself on unseen test flowers. Now you can use it to identify one fresh flower from four measurements.

A prediction needs the same four features in the same order used during training. A one-row pandas DataFrame preserves that structure for the fitted model.

In this step, get ready to:
  • Create a one-row table containing four new flower measurements.
  • Use the fitted classifier to predict a class index.
  • Translate the predicted class index into a readable species name.
Prepare the flower measurements

The model learned from the columns stored in iris.feature_names. Using those names for the new row keeps every measurement aligned with the correct feature.

  • Add a new code cell directly below Cell 5 in iris_flower_classifier.ipynb.
  • Paste the following code into the new cell:
# Cell 6: Predict a new flower
new_flower = pd.DataFrame(
    [[5.9, 3.0, 5.1, 1.8]],
    columns=iris.feature_names,
)

new_prediction = model.predict(new_flower)[0]
print(f"Predicted species: {iris.target_names[new_prediction]}")

What does this code do?

  • The new_flower variable stores one example as a row with four measurements.
  • The columns=iris.feature_names setting gives the row the same column order used for training.
  • The model.predict(new_flower) call asks the fitted decision tree for a class index.
  • The [0] expression extracts the only result from the returned collection.
  • The iris.target_names value translates that index into a species name for the printed message.
Run and verify the prediction

Before you run the cell, decide which of the three species you expect the model to choose.

  • Run Cell 6 using the run control beside the cell.

You'll see Predicted species: followed by one Iris species name.

You now have a complete path from fresh measurements to a readable flower prediction.

  • Confirm iris_flower_classifier.ipynb has finished saving to Google Drive.

Prediction cell not running?

If the cell reports that an earlier variable is missing, the hosted runtime may have restarted. Run Cells 1 through 5 in order before running Cell 6 again.

If the prediction reports a problem with the input columns, compare the spelling of iris.feature_names with the code above.

Help me debug my new-flower prediction cell.

✔️ Awesome, I've got everything!

Your notebook now contains all six project cells. The final cell prints a human-readable species prediction.

ⓧ I'd like to double check the full code

# Cell 1: Setup
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

print("Data science tools loaded.")

# Cell 2: Load and explore the data
iris = load_iris(as_frame=True)
data = iris.frame.copy()
X = iris.data
y = iris.target

print(f"Rows and columns: {data.shape}")
print("\nFirst five rows:")
print(data.head())
print("\nDescriptive statistics:")
print(data.describe())
print(f"\nTarget names: {list(iris.target_names)}")

# Cell 3: Visualize two useful features
fig, ax = plt.subplots()
ax.scatter(
    X[iris.feature_names[2]],
    X[iris.feature_names[3]],
    c=y,
)
ax.set_xlabel(iris.feature_names[2])
ax.set_ylabel(iris.feature_names[3])
ax.set_title("Iris petal measurements by species")
plt.show()

print(f"Color order: {list(enumerate(iris.target_names))}")

# Cell 4: Establish a simple baseline
baseline_predictions = y * 0
baseline_accuracy = accuracy_score(y, baseline_predictions)
print(f"Baseline accuracy: {baseline_accuracy:.2%}")

# Cell 5: Train and evaluate on separate data
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y,
)

model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
test_predictions = model.predict(X_test)
test_accuracy = accuracy_score(y_test, test_predictions)

comparison = pd.DataFrame(
    {
        "actual": iris.target_names[y_test],
        "predicted": iris.target_names[test_predictions],
    }
)

print(f"Test accuracy: {test_accuracy:.2%}")
print(comparison.head(10))

# Cell 6: Predict a new flower
new_flower = pd.DataFrame(
    [[5.9, 3.0, 5.1, 1.8]],
    columns=iris.feature_names,
)

new_prediction = model.predict(new_flower)[0]
print(f"Predicted species: {iris.target_names[new_prediction]}")