Mathew K Analytics

Lesson 4 · Python For Machine Learning

2 Train-Test Split in Python: Step-by-Step Guide for Machine Learning Beginners

Welcome! Today you will learn how to split data for machine learning. We'll practice using simple examples and a real dataset. By the end, you'll be ready…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb
 

Train Test Split in Python: A Beginner's Guide#

Welcome! Today you will learn how to split data for machine learning.

We'll practice using simple examples and a real dataset.

By the end, you'll be ready to split data like a pro!

# Let's start by telling Python to silence warnings.
import warnings
warnings.filterwarnings("ignore")

Why split data?#

Machine learning models need to learn and to be tested.

Splitting data helps you check if your model can really predict new things.

You train on one part and test on another!

# Let's import the tools we need.
import pandas as pd
from sklearn.model_selection import train_test_split

Example: A Simple List Split#

Let's try splitting a tiny list before we use real data.

This will help you see what splitting is all about.

# Make a list of numbers from 0 to 9.
numbers = list(range(10))
print("Numbers:", numbers)
Numbers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Split our list into two parts.
train, test = train_test_split(numbers, test_size=0.3, random_state=42)
print("Train:", train)
print("Test:", test)
Train: [0, 7, 2, 9, 4, 3, 6]
Test: [8, 1, 5]

That's it! Splitting data works for all kinds of data, not just lists.

Next, let's use a real-world dataset: The Titanic passengers.

# Data setup: Load Titanic data from a CSV file.
url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
df = pd.read_csv(url)
print("Shape:", df.shape)
df.head()
Shape: (891, 12)
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
# Let's see how many people survived and how many did not.
df["Survived"].value_counts()
Survived
0    549
1    342
Name: count, dtype: int64
# Split Titanic data into features and labels.
X = df.drop("Survived", axis=1)
y = df["Survived"]

Now it's time for the real split!

We will keep 20 percent of the data for testing.

Random state makes our split repeatable.

# Split Titanic data into training and testing sets.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print("Train features shape:", X_train.shape)
print("Test features shape:", X_test.shape)
Train features shape: (712, 11)
Test features shape: (179, 11)
# Check the training and test target balance.
print("Train set survival:")
print(y_train.value_counts(normalize=True))
print("Test set survival:")
print(y_test.value_counts(normalize=True))
Train set survival:
Survived
0    0.623596
1    0.376404
Name: proportion, dtype: float64
Test set survival:
Survived
0    0.586592
1    0.413408
Name: proportion, dtype: float64
# Try splitting with user choices.
split = float(input("Enter test size as a decimal (try 0.25): "))
X_train2, X_test2, y_train2, y_test2 = train_test_split(X, y, test_size=split, random_state=42)
print("Train shape:", X_train2.shape, "Test shape:", X_test2.shape)
Train shape: (668, 11) Test shape: (223, 11)
 

Practice prompt: Change the random_state number#

See if your splits change.

Try different numbers and compare train and test shapes.

# Challenge: What happens if you skip random_state?
split1 = train_test_split(X, y, test_size=0.3)
split2 = train_test_split(X, y, test_size=0.3)
print("Same split?", (split1[0] == split2[0]).all())
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_33604\3364846154.py in ?()
      1 # Challenge: What happens if you skip random_state?
      2 split1 = train_test_split(X, y, test_size=0.3)
      3 split2 = train_test_split(X, y, test_size=0.3)
----> 4 print("Same split?", (split1[0] == split2[0]).all())

c:\Users\makmw\AppData\Local\Programs\Python\Python312\Lib\site-packages\pandas\core\ops\common.py in ?(self, other)
     72                     return NotImplemented
     73 
     74         other = item_from_zerodim(other)
     75 
---> 76         return method(self, other)

c:\Users\makmw\AppData\Local\Programs\Python\Python312\Lib\site-packages\pandas\core\arraylike.py in ?(self, other)
     38     @unpack_zerodim_and_defer("__eq__")
     39     def __eq__(self, other):
---> 40         return self._cmp_method(other, operator.eq)

c:\Users\makmw\AppData\Local\Programs\Python\Python312\Lib\site-packages\pandas\core\frame.py in ?(self, other, op)
   7901     def _cmp_method(self, other, op):
   7902         axis: Literal[1] = 1  # only relevant for Series other case
   7903 
-> 7904         self, other = self._align_for_op(other, axis, flex=False, level=None)
   7905 
   7906         # See GH#4537 for discussion of scalar op behavior
   7907         new_data = self._dispatch_frame_op(other, op, axis=axis)

c:\Users\makmw\AppData\Local\Programs\Python\Python312\Lib\site-packages\pandas\core\frame.py in ?(self, other, axis, flex, level)
   8199                     left, right = left.align(
   8200                         right, join="outer", level=level, copy=False
   8201                     )
   8202                 else:
-> 8203                     raise ValueError(
   8204                         "Can only compare identically-labeled (both index and columns) "
   8205                         "DataFrame objects"
   8206                     )

ValueError: Can only compare identically-labeled (both index and columns) DataFrame objects
# Best practice: Always set random_state for repeats.
split3a = train_test_split(X, y, test_size=0.3, random_state=99)
split3b = train_test_split(X, y, test_size=0.3, random_state=99)
print("Same split?", (split3a[0] == split3b[0]).all())
Same split? PassengerId     True
Pclass          True
Name            True
Sex             True
Age            False
SibSp           True
Parch           True
Ticket          True
Fare            True
Cabin          False
Embarked       False
dtype: bool
# What if your label is not balanced?
from sklearn.model_selection import StratifiedShuffleSplit
sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_idx, test_idx in sss.split(X, y):
    Xs_train, Xs_test = X.iloc[train_idx], X.iloc[test_idx]
    ys_train, ys_test = y.iloc[train_idx], y.iloc[test_idx]
print("Stratified train label freq:")
print(ys_train.value_counts(normalize=True))
print("Stratified test label freq:")
print(ys_test.value_counts(normalize=True))
Stratified train label freq:
Survived
0    0.616573
1    0.383427
Name: proportion, dtype: float64
Stratified test label freq:
Survived
0    0.614525
1    0.385475
Name: proportion, dtype: float64
# Quick tip: Shuffle your data for fairness.
df_shuffled = df.sample(frac=1, random_state=24)
df_shuffled.head()
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
169 170 0 3 Ling, Mr. Lee male 28.0 0 0 1601 56.4958 NaN S
556 557 1 1 Duff Gordon, Lady. (Lucille Christiana Sutherl... female 48.0 1 0 11755 39.6000 A16 C
206 207 0 3 Backstrom, Mr. Karl Alfred male 32.0 1 0 3101278 15.8500 NaN S
71 72 0 3 Goodwin, Miss. Lillian Amy female 16.0 5 2 CA 2144 46.9000 NaN S
677 678 1 3 Turja, Miss. Anna Sofia female 18.0 0 0 4138 9.8417 NaN S

Mini-project: Predicting Titanic survival#

Let's use everything you learned so far.

In this part, we will:

  • Prepare the data
  • Split into train/test sets
  • Print out the shapes
  • Show target distribution

You are ready to practice!

# Step 1: Remove rows with missing age values.
df_clean = df.dropna(subset=["Age"])
print("Rows left:", df_clean.shape[0])
Rows left: 714
# Step 2: Prepare features and labels again.
X_mini = df_clean.drop("Survived", axis=1)
y_mini = df_clean["Survived"]
# Step 3: Split and check label proportions.
X_train_m, X_test_m, y_train_m, y_test_m = train_test_split(
    X_mini, y_mini, test_size=0.3, random_state=7
)
print("Train size:", X_train_m.shape[0], "Test size:", X_test_m.shape[0])
print("Train survive %:", y_train_m.mean().round(2), "Test survive %:", y_test_m.mean().round(2))
Train size: 499 Test size: 215
Train survive %: 0.4 Test survive %: 0.41

Challenge: Try it with a different dataset#

Can you split the data from another famous dataset?

Try the Iris dataset from sklearn for practice.

Recap#

You learned why and how to split data.

You tried on lists and real tables.

Using train_test_split is the first step for model testing.

Keep trying more datasets for better skills.

If you found this helpful, please like and subscribe.

Try out a split now for practice!

What project will you split data for next?

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.