EDA and Feature Engineeringpandas 3.0 · scikit-learn 1.9 · seaborn 0.13 · Python 3.12+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
72 small wins to finish your pathNext lesson →

Min max scaling

Min max scaling rewrites a column as (x − minimum) / (maximum − minimum), so every value lands between 0 and 1.

Last updated: 12 Oct, 2026 · pandas 3.0 · scikit-learn 1.9 · scipy 1.18

Standardisation centred each column at zero and left its range open. Min max scaling fixes the range instead and lets the centre fall where it may. It is the scaling used on image pixels, where dividing by 255 is this formula with a minimum of 0.

Min max scaling · from the Live Feature Engineering sessions · 43:05 to 47:20
The smallest value maps to 0 and the largest to 1

Syntax: the same three calls as every scaler, with a feature_range argument if 0 to 1 is not what you want.

python
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()              # feature_range=(0, 1) by default
out = scaler.fit_transform(df)

Scaling the four Titanic columns

The same four columns as before, with the median filled into Age, so the two scalers can be compared row for row.

python
import pandas as pd

URL = "https://raw.githubusercontent.com/krishnaik06/Feature-Engineering-Live-sessions/master/titanic.csv"
df = pd.read_csv(URL, usecols=['Survived', 'Pclass', 'Age', 'Fare'])
df['Age'] = df['Age'].fillna(df['Age'].median())   # 177 missing ages, filled with 28.0
python
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler().set_output(transform='pandas')
scaled = scaler.fit_transform(df)

Putting every column between 0 and 1

ExampleThe same four columns, scaled to 0 and 1 on scikit-learn 1.9.1
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler().set_output(transform='pandas')
scaled = scaler.fit_transform(df)

print(scaled.head(3).round(6).to_string())
print("\nmin:", scaled.min().tolist())
print("max:", scaled.max().tolist())
print("\nlearned data_min_:", scaler.data_min_.tolist())
print("learned data_max_:", scaler.data_max_.tolist())
low, high = scaler.data_min_[2], scaler.data_max_[2]
print("first age by hand:", round((df.loc[0, "Age"] - low) / (high - low), 6))

Reading the scaled columns

  • Every column runs from 0.0 to 1.0 exactly. That is guaranteed on the data the scaler was fitted on, and only on that data.
  • data_min_ and data_max_ are what it learned: the smallest and largest value of each column, 0.42 and 80.0 for Age.
  • The first fare is 0.014151, which says that a fare of 7.25 sits one and a half percent of the way from the cheapest ticket to the most expensive one.
  • Pclass comes through as 0, 0.5 and 1, and Survived as 0 and 1. A column with three levels gets three evenly spaced values, which is worth noticing before an already encoded category is handed to a scaler.

Where the extreme fare sends the rest

One passenger paid 512.33 while the median fare is 14.45. That single value sets data_max_, and every other fare is measured against it.

ExampleBoth columns after the same transform
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 2, figsize=(9, 3.4))
ax[0].hist(scaled["Age"], bins=20, color="#3a6fd8")
ax[0].set_title("Age after min max scaling")
ax[1].hist(scaled["Fare"], bins=20, color="#d8733a")
ax[1].set_title("Fare after min max scaling")
for a in ax:
    a.set_xlabel("scaled value"); a.set_ylabel("passengers")
fig.tight_layout()

print("median fare lands at :", round(scaled["Fare"].median(), 4))
print("share of fares below 0.1:", f"{(scaled['Fare'] < 0.1).mean():.1%}")
print("median age lands at  :", round(scaled["Age"].median(), 4))
Two histograms after min max scaling: Age spreads across the whole 0 to 1 axis, while Fare is a single tall bar at the left edge with the remaining values spread thinly to the right.
  • The median fare lands at 0.0282. Half the passengers sit in the bottom three percent of the scaled range, because the range belongs to one ticket.
  • 82.2% of fares fall below 0.1. The transform did what it promised and still left the column unusable for anything that compares distances.
  • Age is unaffected because it has no such extreme. Min max scaling is only as good as the two values it learns.

Min max scaling compared with standardisation

MinMaxScalerStandardScaler
Formula(x − min) / (max − min)(x − mean) / standard deviation
Output range0 to 1, guaranteed on the fitted dataopen, usually about −3 to 3
Learnsthe minimum and the maximumthe mean and the standard deviation
Effect of one extreme valuesets the whole range, squeezes everything elsemoves the mean and the standard deviation a little
New value outside the fitted rangegoes below 0 or above 1goes further from 0, nothing special happens
Usual homeimage pixels, neural network inputsmost other models

Where min max scaling is used

  • Image pixels. Values arrive as 0 to 255 and are divided by 255, which is this formula with a minimum of 0 and a maximum of 255.
  • Neural network inputs, where a bounded input range keeps the first layer's activations in a sensible place.
  • Anything that must be read as a proportion, such as a score shown to a user as a percentage of the observed range.
Watch out. The 0 to 1 promise only covers the rows the scaler was fitted on. A test fare larger than 512.33 transforms to more than 1, and a negative value is possible too. That is correct behaviour, not a bug, and it is why a column with extreme values is usually better served by Robust scaling.
Try it yourself
  • Pass feature_range=(-1, 1) and read the minimum and maximum again.
  • Transform a one row frame with a fare of 600 using the fitted scaler. The result is larger than 1.
  • Drop the one passenger who paid 512.33 before fitting, then look at where the median fare lands. It moves a long way up.

Slow is fine. Stopping is the only problem.