API · Pandas

Pandas cut Function

This tutorial explains how we can distribute data into ranges also called bins using the pandas.cut() function.

On this page

The pandas.cut() function assigns numeric values to ranges, also called bins. It returns one interval category for each input value, making it useful for turning continuous measurements such as ages or scores into groups for analysis. You can provide explicit cut points or ask pandas to divide a range into a chosen number of bins.

Syntax, parameters, and return value

The function call is pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates="raise", ordered=True).

The arguments most often used are:

Parameter Description
x Array-like numeric values to assign, such as a list, Series, or DataFrame column.
bins An integer number of equal-width bins, a sequence of explicit cut points, or an IntervalIndex. With an integer, pandas derives the range from the minimum and maximum of x, divides it into that many equal-width bins, and extends the range by 0.1% on each side so both endpoint values are included. A sequence supplies the cut points directly and does not use this integer-bin range adjustment.
right When True (the default), intervals include their right endpoint. Set to False for left-closed intervals.
labels Optional labels, one for each bin. Use False to return integer bin positions.
retbins When True, also return the cut points used to form the bins.
precision Precision used for storing and displaying the cut points.
include_lowest When True, include the lowest cut point in the first interval.
duplicates Choose "raise" (the default) or "drop" when cut points contain duplicate values.
ordered Whether the resulting categories are ordered; defaults to True.

Normally the result has one categorical value for every item in x. A value outside all intervals is represented by NaN. With retbins=True, the function returns a pair: the per-value result and the array of cut points.

Assign DataFrame values to bins

Pass a DataFrame column as x, provide the interval cut points through bins, and assign the returned Series to a new column. Run this example:

import pandas as pd

df = pd.DataFrame(
    {
        "Name": ["Anish", "Birat", "Chirag", "Kabin", "Sachin"],
        "Age": [23, 34, 38, 45, 27],
        "Score": [316, 322, 332, 330, 325],
    }
)

df["Age-Range"] = pd.cut(df["Age"], bins=[20, 30, 40, 50])
print(df[["Age", "Age-Range"]].to_string(index=False))

There are three bins because four cut points define three intervals. Each row keeps its original position, and its Age-Range value identifies the interval containing that row’s age. For example, age 23 maps to (20, 30], while age 45 maps to (40, 50] with the default interval convention.

Control interval boundaries

By default, right=True creates right-closed intervals. The notation (20, 30] means values greater than 20 and up to and including 30: 20 is excluded and 30 is included. include_lowest=True also includes the lowest cut point in the first interval. Set right=False to use left-closed, right-open intervals such as [20, 30), which include 20 and exclude 30. Under that setting, the highest cut point is outside the last interval. Values that match no interval are returned as NaN.

The following example compares those options for ages at and between the supplied cut points:

import pandas as pd

ages = pd.Series([20, 23, 30, 45, 50], name="Age")
result = pd.DataFrame(
    {
        "Age": ages,
        "default": pd.cut(ages, bins=[20, 30, 40, 50]),
        "include_lowest": pd.cut(
            ages, bins=[20, 30, 40, 50], include_lowest=True
        ),
        "left_closed": pd.cut(
            ages, bins=[20, 30, 40, 50], right=False
        ),
    }
)
print(result.to_string(index=False))

Compare the rows for 20 and 50 to see how the endpoint choices affect membership. The default includes 50 in the last interval but excludes 20 from the first; include_lowest=True adds 20 to that first interval, while right=False includes 20 and leaves 50 outside the final interval.

Assign labels to the bins

To show readable category names instead of interval notation, pass a label for each bin. The labels follow the interval order, so three bins require three labels:

import pandas as pd

ages = pd.Series([23, 34, 38, 45, 27], name="Age")
labels = ["21 to 30", "31 to 40", "41 to 50"]
age_groups = pd.cut(
    ages,
    bins=[20, 30, 40, 50],
    labels=labels,
)
print(age_groups.to_string(index=False))

The first label belongs to (20, 30], the second to (30, 40], and the third to (40, 50] under the defaults. If you need numeric group positions instead of names, pass labels=False; pandas then returns integer bin codes for values assigned to a bin.

Return the bin edges with retbins=True

Set retbins=True when you need both the per-value categories and the cut points used for them. The first returned item corresponds to x; the second is the shared array of bin edges. This example unpacks both:

import pandas as pd

ages = pd.Series([23, 34, 38, 45, 27], name="Age")
age_groups, bin_edges = pd.cut(
    ages,
    bins=[20, 30, 40, 50],
    labels=["21 to 30", "31 to 40", "41 to 50"],
    retbins=True,
)
print("Groups:")
print(age_groups.to_string(index=False))
print("Bin edges:")
print(bin_edges)

age_groups contains one labeled result per age, while bin_edges contains [20, 30, 40, 50]. The same pattern is useful when bins is an integer and pandas computes equal-width cut points: retain the returned edges if you need to inspect or reuse them.