Flower Species Classifier in Python
Train ML models to classify iris flowers by species using scikit-learn.
Introduction
30 Second Summary
You already know how to classify things. You see a bird with a red chest and know it's a robin. You notice a dog's floppy ears and short legs and guess it's a beagle. Machine learning does the same thing, but with data instead of eyeballs.
In this project, you will train a classification model to identify iris flower species based on petal and sepal measurements. You'll compare three different algorithms, discover a common beginner trap called overfitting, and make predictions on brand new flowers your model has never seen.
What You'll Build
You'll hand your model a set of flower measurements, watch it predict the species, and see a confidence percentage telling you how sure it is.
By the end of this project, you'll have:
- A trained model that takes new flower measurements and predicts the species with a confidence score.
- A visual bar chart comparing three algorithms side-by-side so you can see which one performs best.
- A working understanding of the complete ML workflow that every ML engineer uses: load data, explore, split, train, evaluate, and compare.
- Secret Mission: Build a scikit-learn Pipeline with feature scaling and cross-validation for production-ready evaluation.
Are there any prerequisites?
You should be comfortable with basic Python concepts like variables, functions, and loops. No prior machine learning experience is needed.
Before We Start
Before We Start...
Before we dive in, let's lock in what you're about to build and why it matters for your ML engineering journey.
Set Up Your ML Environment
Before you can train a machine learning model, you need the right tools in place. Your model will rely on three core Python libraries to load data, learn patterns, and visualize results.
In this step, you will create a dedicated project folder, set up an isolated Python environment, and install scikit-learn, pandas, and matplotlib.
In this step, get ready to:
- Create a project folder and virtual environment.
- Install scikit-learn, pandas, and matplotlib.
- Verify all three libraries are working.
Create your project folder and virtual environment
- In VS Code, press Ctrl+` (backtick) to open the integrated terminal.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir iris-classifier
cd iris-classifier
Your terminal prompt now shows iris-classifier in the path.
- Create a virtual environment by running this command:
python -m venv venv
- Confirm the venv folder was created by running:
ls
You should see a venv folder listed in the output.
What is a virtual environment?
A virtual environment is an isolated space where Python installs packages just for this project. It keeps your project's dependencies separate from other Python projects on your machine.
- Activate the virtual environment so packages install into it.
macOS
- Activate the environment by running:
source venv/bin/activate
Windows
- Activate the environment by running:
venv\Scripts\activate
You should see (venv) appear at the start of your terminal prompt. This confirms the virtual environment is active.
Don't see (venv) in your prompt?
- Make sure you ran the activate command for your operating system (macOS uses source, Windows uses the Scripts path).
- If you see python: command not found when creating the venv, try using python3 instead.
- Help me troubleshoot
Install the required libraries
With your virtual environment active, any packages you install will stay scoped to this project.
- Install scikit-learn, pandas, and matplotlib by running:
pip install scikit-learn pandas matplotlib
You will see progress bars as each package downloads and installs along with its dependencies.
What are these libraries for?
- scikit-learn provides the machine learning algorithms you will train and evaluate.
- pandas makes it easy to load, explore, and manipulate your dataset in table form.
- matplotlib creates charts and visualizations so you can see patterns in your data.
Seeing an error during install?
- If you see a permissions error, make sure (venv) is showing in your prompt. Installing without an active venv may require admin privileges.
- If you see a network timeout, check your internet connection and run the install command again.
- Help me fix my install error
Verify your installation
Before you move on, you need to confirm all three libraries import correctly and are ready to use.
- What do you expect to see if everything installed correctly? Think about it, then verify all three libraries by running:
python -c "import sklearn; print(sklearn.__version__); import pandas; print(pandas.__version__); import matplotlib; print(matplotlib.__version__)"
You should see three version numbers printed, one per line. For example: 1.9.0 for scikit-learn, 3.0.4 for pandas, and 3.11.1 for matplotlib (your exact versions may vary slightly).
Seeing ModuleNotFoundError?
- Check that (venv) is still showing in your prompt. If not, reactivate your virtual environment and try again.
- If only one library fails to import, run pip install followed by that specific library name to reinstall it.
- Help me troubleshoot my import error
Your ML environment is ready to go. Next up, you will load a real flower dataset and explore the patterns hiding inside it.
Load and Explore the Iris Dataset
Your ML environment is ready with all the libraries installed. Now it's time to meet your data.
You cannot build a good model without understanding what your data looks like. Exploring first reveals patterns, potential issues, and gives you intuition about what the model will need to learn. In this step, you will load a classic flower measurement dataset and look for visual clues that separate one species from another.
In this step, get ready to:
- Load the Iris dataset and inspect its structure.
- Print summary statistics and confirm balanced classes.
- Create a scatter plot revealing species clusters.
Create your classifier script and load the data
The Iris dataset is built directly into scikit-learn, so there is nothing to download. It contains 150 flower samples with 4 measurements each (sepal length, sepal width, petal length, petal width) across 3 species.
- In VS Code, create a new file called classifier.py inside your iris-classifier folder.
- Paste the following code to import libraries, load the dataset, and print its basic shape:
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
import joblib
# --- Step 2: Load and Explore ---
print("=" * 50)
print("STEP 2: Loading and Exploring the Iris Dataset")
print("=" * 50)
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df["species"] = iris.target
df["species_name"] = df["species"].apply(lambda x: iris.target_names[x])
print(f"\nDataset shape: {df.shape}")
print(f"Features: {iris.feature_names}")
print(f"Target classes: {list(iris.target_names)}")
What does this code do?
The imports at the top pull in every library you will use across this project. You import them all now so you won't need to revisit this section later.
- load_iris() returns a Bunch object containing the raw measurement arrays, feature names, and target labels.
- You wrap the arrays in a pandas DataFrame so you can view the data in a familiar table format.
- The species column stores numeric class labels (0, 1, 2) while species_name maps those to readable names (setosa, versicolor, virginica).
- Save classifier.py.
- Run the script in your terminal:
python classifier.py
You should see a banner header, then the dataset shape printed as (150, 6), four feature names, and three target classes.
Seeing a ModuleNotFoundError?
This means your virtual environment is not active. Check that your terminal prompt starts with (venv). If not, activate it again:
venv\Scripts\activate
Then re-run python classifier.py. Still stuck? Help me fix this ModuleNotFoundError in my iris classifier project.
Explore the data with statistics
Printing rows and summary statistics tells you whether the data is clean and balanced before you train anything.
- In classifier.py, add the following code below the last print line:
print(f"\nFirst 5 rows:")
print(df.head())
print(f"\nBasic statistics:")
print(df.describe())
print(f"\nClass distribution:")
print(df["species_name"].value_counts())
What does this code do?
- df.head() prints the first 5 rows so you can eyeball the raw measurements.
- df.describe() gives you mean, min, max, and standard deviation for each feature column.
- value_counts() confirms the dataset has exactly 50 samples per species, meaning it is perfectly balanced.
- Save classifier.py and run it again:
python classifier.py
You should now see a table of the first 5 rows, statistics for all features, and each species listed with a count of 50.
Output looks garbled or cut off?
If the DataFrame table wraps oddly in your terminal, try making your terminal panel wider by dragging the edge. The data is still correct even if the columns don't align perfectly on narrow screens. Help me read the pandas output in my terminal.
Visualize patterns with a scatter plot
Numbers alone can hide patterns that a chart makes obvious. A scatter plot of two features will reveal how separable the species actually are.
- In classifier.py, add the following code below the value_counts() line:
# Scatter plot
plt.figure(figsize=(8, 6))
for i, species in enumerate(iris.target_names):
subset = df[df["species"] == i]
plt.scatter(
subset["petal length (cm)"],
subset["petal width (cm)"],
label=species,
)
plt.xlabel("Petal Length (cm)")
plt.ylabel("Petal Width (cm)")
plt.title("Iris Dataset: Petal Length vs Petal Width")
plt.legend()
plt.savefig("exploration.png")
plt.close()
print("\nScatter plot saved as exploration.png")
What does this code do?
The loop draws one cluster of dots per species, using petal length on the x-axis and petal width on the y-axis. Each species gets its own color automatically.
plt.savefig("exploration.png") writes the chart to a file rather than opening a GUI window. plt.close() frees the memory so the script exits cleanly.
- Save classifier.py.
Before you run this, what do you think the scatter plot will show? Will all three species form completely separate clusters, or will some overlap?
- Run the script:
python classifier.py
At the bottom of the output, you should see the message Scatter plot saved as exploration.png.
- Confirm the file was created by running:
ls exploration.png
You should see exploration.png listed. Open the file in VS Code or your file manager to see the chart.
What does the scatter plot reveal?
Setosa (one cluster) sits completely apart from the other two species. Versicolor and virginica overlap in the middle, meaning the model will have a harder time distinguishing those two. This is the classification challenge your model needs to solve.
Don't see exploration.png?
Make sure you are running python classifier.py from inside the iris-classifier folder. The file saves to whichever directory your terminal is currently in. Run pwd to check your current location. Help me find my exploration.png file.
✔️ Awesome, I've got everything!
Great. Double check you have saved classifier.py and that exploration.png exists in your project folder.
ⓧ I'd like to double check the full code
Scroll up and confirm your classifier.py contains these sections in order:
- All import statements at the top (pandas, matplotlib, sklearn modules, joblib).
- The "Step 2: Load and Explore" header prints and DataFrame creation code.
- The head(), describe(), and value_counts() print statements.
- The scatter plot block ending with print("\nScatter plot saved as exploration.png").
You have loaded a real dataset, confirmed it has 150 balanced samples across 3 species, and created a visualization that reveals where your future model will struggle. Next up, you will train your first model and discover why testing on training data gives dangerously misleading results.
Train Your First Model and Discover the Overfitting Trap
Your dataset is loaded and you've spotted patterns in the scatter plot. Time to train a model to classify flower species from measurements.
There's a fundamental question every ML engineer must answer: how do you honestly measure whether a model learned useful patterns? You'll discover why the most obvious evaluation approach gives dangerously misleading results.
In this step, get ready to:
- Train a Decision Tree classifier on the full Iris dataset.
- Introduce train/test splitting for honest evaluation.
- Identify overfitting and understand why it's dangerous.
Train a Decision Tree on all the data
A DecisionTreeClassifier learns rules from your data to sort flowers into species. Let's train one on all 150 samples and check its accuracy score.
- In classifier.py, scroll to the bottom of the file (below the print("\nScatter plot saved as exploration.png") line).
- Add the following code to train your first model:
# --- Step 3: Train and Discover Overfitting ---
print("\n" + "=" * 50)
print("STEP 3: Training and Discovering the Overfitting Trap")
print("=" * 50)
X = iris.data
y = iris.target
# The trap: train and test on ALL data
tree_all = DecisionTreeClassifier(random_state=42)
tree_all.fit(X, y)
score_all = accuracy_score(y, tree_all.predict(X))
print(f"\nAccuracy (trained and tested on ALL data): {score_all:.4f}")
print("Looks perfect! But this is misleading...")
What does this code do?
- X = iris.data stores the 150 rows of flower measurements (the inputs your model learns from).
- y = iris.target stores the 150 species labels (the answers your model tries to predict).
- tree_all.fit(X, y) trains the Decision Tree on every sample.
- accuracy_score(y, tree_all.predict(X)) measures how many predictions match the real labels. The catch is you're testing on the same data you trained on.
Before you run this, what accuracy score do you think the model will achieve on data it was trained on?
- Save classifier.py and run your script:
python classifier.py
Scroll to the Step 3 output. You'll see an accuracy of 1.0000 (100%). The model got every single prediction right.
That score is a lie. You just asked the model to answer questions it already had the answer sheet for. It memorized the data instead of learning patterns.
What is overfitting?
Overfitting is when a model memorizes training data so perfectly that it fails on new, unseen data. A 100% score on training data is a red flag, not a celebration.
Think of it like studying only the answers to a practice exam. You'd ace that exact exam, but fail any exam with different questions.
Split the data to get an honest score
To honestly evaluate your model, you need to test it on data it has never seen before. The train_test_split function reserves a portion of the data for testing only.
- Add this code directly below the previous section in classifier.py:
# The fix: train/test split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
tree_split = DecisionTreeClassifier(random_state=42)
tree_split.fit(X_train, y_train)
train_accuracy = accuracy_score(y_train, tree_split.predict(X_train))
test_accuracy = accuracy_score(y_test, tree_split.predict(X_test))
print(f"\nWith train/test split (80/20):")
print(f" Training accuracy: {train_accuracy:.4f}")
print(f" Test accuracy: {test_accuracy:.4f}")
print(
"\nThe test accuracy is the honest score. The model was memorizing, not learning!"
)
What does this code do?
- train_test_split holds back 20% of the data (30 samples) that the model never sees during training.
- random_state=42 ensures the split is the same every time you run the script, so your results are reproducible.
- The model trains on 80% (120 samples), then predicts on the hidden 20%. The test accuracy is the honest score because the model has never seen those flowers before.
What do you think the test accuracy will be compared to the training accuracy? Will it still be 100%?
- Save classifier.py and run the script again:
python classifier.py
Scroll to the bottom of the output. You'll see the training accuracy remains high, but the test accuracy is lower. That gap is the overfitting your first score was hiding.
Why is the train/test split essential?
The test accuracy is the only number that tells you how your model performs on flowers it has never encountered. This is the score that matters for real-world use.
Every ML project uses this split. Without it, you have no idea if your model actually learned generalizable patterns or just memorized the training examples.
Seeing the same 1.0 for both scores?
- Make sure you created a new tree_split classifier and called .fit(X_train, y_train) (training set only, not X and y).
- Confirm you're evaluating with X_test and y_test for the test accuracy, not the full dataset.
- Check that test_size=0.2 is set in your train_test_split call.
Why is my model still showing 100% on the test set?
✔️ Awesome, I've got everything!
Great. Double check you've saved classifier.py and both accuracy sections are printing correctly.
ⓧ I'd like to double check the full code
Your classifier.py should now have these sections in order. Scroll through your file and confirm each is present:
- Imports at the top (pandas, matplotlib, sklearn modules, joblib).
- Step 2 section: loading the Iris dataset, printing stats, creating the scatter plot.
- Step 3 section header printing the title.
- X and y assigned from iris.data and iris.target.
- The trap: tree_all trained on all data, score_all printed.
- The fix: train_test_split creating X_train, X_test, y_train, y_test.
- tree_split trained on X_train only, with train_accuracy and test_accuracy printed.
- Final print statement naming overfitting.
You just experienced the most important lesson in machine learning: a model that scores perfectly on its training data might be useless on new data. Next up, you'll compare multiple algorithms to find which one genuinely performs best on unseen flowers.
Compare Multiple Algorithms
In the last step, you discovered the overfitting trap and learned that train/test splitting gives you honest accuracy scores. You now have a reliable evaluation method.
But which algorithm should you use? Different algorithms learn patterns in fundamentally different ways. A Decision Tree splits data based on feature thresholds, while a KNN model looks at nearby neighbors, and a Random Forest aggregates many trees. In this step, you'll train all three on the same data and compare them head-to-head.
In this step, get ready to:
- Train three different classification algorithms on the same training data.
- Print a comparison table and detailed classification report.
- Create a bar chart visualizing algorithm performance.
Train three classifiers on the training set
Each algorithm approaches classification differently. A Decision Tree splits data by asking yes/no questions about feature values. KNN (K-Nearest Neighbors) classifies a sample by looking at the closest training examples. A Random Forest builds many decision trees and takes a vote.
- In classifier.py, scroll to the bottom of your file (after the Step 3 code) and add the following code to define and train all three models:
# --- Step 4: Compare Multiple Algorithms ---
print("\n" + "=" * 50)
print("STEP 4: Comparing Multiple Algorithms")
print("=" * 50)
models = {
"Decision Tree": DecisionTreeClassifier(random_state=42),
"KNN (k=5)": KNeighborsClassifier(n_neighbors=5),
"Random Forest": RandomForestClassifier(n_estimators=100, random_state=42),
}
results = {}
for name, model in models.items():
model.fit(X_train, y_train)
score = accuracy_score(y_test, model.predict(X_test))
results[name] = score
What does this code do?
- models is a dictionary mapping friendly names to fresh classifier objects. Each uses random_state=42 so your results are reproducible.
- The loop trains each model on X_train and scores it against X_test. This ensures every algorithm is evaluated on the exact same unseen data, making the comparison fair.
Print the comparison table and classification report
- Add this code below the training loop to print a formatted table, identify the best algorithm, and show a detailed classification report:
print("\nAlgorithm Comparison:")
print("-" * 35)
for name, score in results.items():
print(f" {name:20s}: {score:.4f}")
best_name = max(results, key=results.get)
best_score = results[best_name]
print(f"\nBest algorithm: {best_name} ({best_score:.4f})")
best_model = models[best_name]
print(f"\nClassification Report for {best_name}:")
print(classification_report(y_test, best_model.predict(X_test), target_names=iris.target_names))
What does this code do?
- max(results, key=results.get) finds the dictionary key with the highest accuracy score.
- classification_report shows precision, recall, and f1-score per species. This reveals exactly which flowers the model confuses (likely versicolor and virginica, based on the overlap you saw in your scatter plot).
- Save classifier.py.
- Run your script to see the comparison table by running:
python classifier.py
Scroll to the Step 4 output. You should see a formatted table showing each algorithm's accuracy, the best algorithm named, and a classification report with per-species precision, recall, and f1-score.
Seeing a NameError or KeyError?
- If you see NameError: name 'X_train' is not defined, make sure your Step 3 code with the train_test_split call is still intact above your new code.
- Check that you pasted the new code AFTER the Step 3 section, not inside it.
Help me debug my classifier comparison code.
Create a bar chart comparing algorithm accuracies
Numbers in a table are useful, but a chart makes the comparison instantly visual. You'll create a bar chart that shows all three algorithms side by side.
- Add this code at the bottom of classifier.py to generate and save the comparison chart:
plt.figure(figsize=(8, 5))
plt.bar(results.keys(), results.values(), color=["steelblue", "coral", "seagreen"])
plt.ylabel("Accuracy")
plt.title("Algorithm Comparison on Iris Dataset")
plt.ylim(0.8, 1.05)
plt.savefig("comparison.png")
plt.close()
print("Comparison chart saved as comparison.png")
What does this code do?
- plt.bar() creates a bar chart using the algorithm names as x-axis labels and their accuracy scores as bar heights.
- plt.ylim(0.8, 1.05) zooms the y-axis to the 0.8-1.0 range so small accuracy differences between algorithms are visually clear.
- Save classifier.py.
Before you run this, which algorithm do you think will come out on top? Will the simple Decision Tree beat the ensemble Random Forest, or will the extra complexity pay off?
- Run your script one more time:
python classifier.py
At the very end of the output, you should see the line Comparison chart saved as comparison.png. Open comparison.png from your iris-classifier folder to see the three algorithms compared visually as colored bars.
Don't see comparison.png?
- Make sure you saved classifier.py before running. Unsaved changes won't execute.
- Check that the chart code is pasted after the classification report code, not inside a different block.
- Confirm the file ran without errors. If there's a SyntaxError, check for missing quotes or parentheses in the lines you just added.
Help me fix my matplotlib bar chart code.
✔️ Awesome, I've got everything!
Great. Double check you've saved classifier.py and that both the comparison table output and comparison.png look correct.
ⓧ I'd like to double check the full code
Your classifier.py should now contain all of the following sections in order. Scroll through your file and confirm each one is present:
- Import statements at the top (pandas, matplotlib, sklearn modules, joblib).
- Step 2: Load and explore section (dataset loading, printing stats, scatter plot saved as exploration.png).
- Step 3: Overfitting trap section (training on all data, then train/test split).
- Step 4: Compare algorithms section (models dictionary, training loop, comparison table, classification report, bar chart saved as comparison.png).
Why compare multiple algorithms?
No single algorithm wins on every dataset. A Decision Tree might overfit on complex data, while KNN might struggle with high-dimensional features. By comparing them on the same test set, you build intuition about which approaches suit which problems.
This compare-and-select workflow is something ML engineers do on every project. The specific algorithms change, but the process stays the same.
You now have three trained models compared fairly on the same test data, with a clear winner identified. Next up, you'll put that best model to work by feeding it brand-new flower measurements and seeing its predictions in action.
Make Predictions on New Data
Your algorithm comparison revealed a winner, and you have a trained model ready to go. Now it's time to put that model to work on data it has never seen before.
A model that only scores well on the test set is still theoretical. The real proof is whether it can classify completely new flower measurements and tell you how confident it is about each prediction.
In this step, get ready to:
- Feed your best model completely new flower measurements and see its predictions.
- Examine the model's confidence scores for each prediction.
- Save the trained model to disk so it can be reused without retraining.
Predict species for new flower measurements
Your best model learned patterns from 120 training samples. Now you will give it measurements it has never encountered and ask it to classify them.
- In classifier.py, scroll to the very bottom of the file (after the comparison chart code).
- Add the following code to define new flower measurements and make predictions:
# --- Step 5: Make Predictions on New Data ---
print("\n" + "=" * 50)
print("STEP 5: Making Predictions on New Data")
print("=" * 50)
new_flowers = [
[5.1, 3.5, 1.4, 0.2],
[6.2, 2.8, 4.8, 1.8],
[5.9, 3.0, 5.1, 1.8],
]
predictions = best_model.predict(new_flowers)
probabilities = best_model.predict_proba(new_flowers)
print("\nPredictions for new flowers:")
print("-" * 60)
for i, flower in enumerate(new_flowers):
species = iris.target_names[predictions[i]]
confidence = probabilities[i][predictions[i]] * 100
print(f" Flower {i+1} {flower}")
print(f" Predicted: {species} (confidence: {confidence:.1f}%)")
print(f" All probabilities: {dict(zip(iris.target_names, [f'{p:.2f}' for p in probabilities[i]]))}")
What does this code do?
- new_flowers is a list of three flower measurements (sepal length, sepal width, petal length, petal width) that do not exist in the original dataset.
- best_model.predict() returns the predicted class (0, 1, or 2) for each flower.
- best_model.predict_proba() returns the probability the model assigns to each of the three species. This is the model's confidence level.
- The loop formats each prediction with the species name and confidence percentage so you can see exactly how sure the model is.
- Save classifier.py.
- Run the script to see the predictions:
python classifier.py
Scroll to the Step 5 section of the output. You should see each new flower's predicted species along with a confidence percentage.
What should I see?
The first flower (small petals: 1.4 cm length, 0.2 cm width) should be classified as setosa with very high confidence. The other two flowers have larger petals and will likely be classified as versicolor or virginica.
Notice the "All probabilities" dictionary for each flower. When the model is uncertain, the probability is spread across multiple species instead of being concentrated on one.
Seeing a NameError for best_model?
Make sure you added this code below the Step 4 section, not above it. The variable best_model is defined in Step 4 and must exist before Step 5 runs.
Help me debug why best_model is not recognized in Step 5 of my iris classifier
Save and load your trained model
Training a model takes time and compute. Saving it to a file means you can load it later and make predictions instantly without retraining.
- Add the following code at the bottom of classifier.py, below the prediction loop you just wrote:
# Save the trained model to disk
joblib.dump(best_model, "iris_model.joblib")
print("\nModel saved as iris_model.joblib")
# Load it back and verify it still works
loaded_model = joblib.load("iris_model.joblib")
verify_prediction = loaded_model.predict([new_flowers[0]])
print(f"Loaded model verification: {iris.target_names[verify_prediction[0]]}")
print("Model save/load working correctly!")
What does this code do?
- joblib.dump() serializes your trained model to a file called iris_model.joblib. This captures the learned patterns so you do not need to retrain.
- joblib.load() reconstructs the model from the file. It is ready to make predictions immediately.
- The verification step feeds the first new flower into the loaded model and confirms it produces the same prediction as before.
Why joblib instead of pickle?
Both joblib and pickle can serialize Python objects. However, joblib is optimized for objects containing large NumPy arrays, which is exactly what trained scikit-learn models contain.
- Save classifier.py.
Before you run the script, what do you think the loaded model will predict for the first flower (the one with small 1.4 cm petals)?
- Run the script to verify the model saves and loads correctly:
python classifier.py
Scroll to the bottom of the output. You should see "Model saved as iris_model.joblib" followed by the loaded model verification confirming the same species prediction.
- Confirm the model file exists on disk by running:
ls
You should see iris_model.joblib alongside classifier.py, exploration.png, and comparison.png.
Not seeing iris_model.joblib?
Make sure your terminal is inside the iris-classifier folder. The file is saved relative to where you run the script.
Also check that you have import joblib at the top of your file. This import was added in Step 2 when you first set up the file.
Help me debug why iris_model.joblib is not being created
✔️ Awesome, I've got everything!
Great. Double check you have saved classifier.py and your script runs without errors all the way through Step 5.
ⓧ I'd like to double check the full code
Your classifier.py is now over 100 lines. Scroll through and confirm these sections are present in order:
- Imports at the top (pandas, matplotlib, sklearn modules, joblib).
- Step 2: Load and Explore (DataFrame creation, prints, scatter plot).
- Step 3: Train and Discover Overfitting (train on all data, then train/test split).
- Step 4: Compare Multiple Algorithms (three models, results dict, bar chart).
- Step 5: Make Predictions on New Data (new_flowers list, predict, predict_proba, print loop, joblib save/load).
If any section is missing or out of order, scroll up in this project and re-add the code from that step.
Your model is trained, tested, and saved. Next up, the Secret Mission challenges you to build a production-ready Pipeline with cross-validation for even more robust evaluation.
Secret mission
Build a Production Pipeline with Cross-Validation
In real ML engineering, a single train/test split is not enough to trust your accuracy score. Build a scikit-learn Pipeline that bundles preprocessing with your model, then evaluate it with 5-fold cross-validation for a production-ready confidence interval.
Clean Up Your Resources
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:
- The iris-classifier project folder on your Desktop (contains all Python files, images, and saved model).
- The venv virtual environment inside the project folder (contains scikit-learn, pandas, and matplotlib).
- Generated files: exploration.png, comparison.png, and iris_model.joblib.
Keep everything running
No action needed. Choose this if you're still actively building or want to experiment further with your classifier.
- Your iris-classifier folder stays on your Desktop with all files intact.
- The virtual environment stays ready. Reactivate it any time with venv\Scripts\activate from inside the project folder.
- Your saved model (iris_model.joblib) can be loaded and used for predictions without retraining.
Pause - I'll come back to this later
Deactivate the virtual environment to free up your terminal session. All files remain on disk for when you return.
- Deactivate your virtual environment by running:
deactivate
- Your project folder and all files remain untouched. When you're ready to resume, navigate back to iris-classifier and reactivate the environment.
Delete - I don't want to use this again
Remove all project files, the virtual environment, and the saved model. This frees up disk space and leaves no trace of the project.
- Deactivate the virtual environment first (if it is still active):
deactivate
- Navigate to your Desktop:
cd ~/Desktop
- Delete the entire project folder (macOS/Linux):
rm -rf iris-classifier
- On Windows, use this command instead:
rmdir /s /q iris-classifier
- This removes classifier.py, classifier_pipeline.py, the venv folder (with all installed packages), the generated images, and the saved model.
Nice Work!
Nice Work!
Nice work! You just built a machine learning classifier that identifies flower species from raw measurements, and you understand the complete workflow that every ML engineer uses on real projects.
You've learned how to:
- Explored a real dataset with pandas and matplotlib, then experienced the overfitting trap firsthand to understand why train/test splitting is essential.
- Trained and compared three classification algorithms (Decision Tree, KNN, Random Forest) on the same test set to find the best performer.
- Made predictions on completely new flower measurements with confidence scores, then saved and loaded a trained model with joblib for reuse without retraining.
- Secret Mission: Built a production-ready Pipeline with StandardScaler and 5-fold cross-validation for robust model evaluation.
Ready to quiz yourself?