Pandasdrill

Grouping and aggregation Updated November 2026

cut and qcut

pd.cut(x, bins, labels) assigns each value to a fixed interval you define (for example age bands), while pd.qcut(x, q) splits values into q groups with roughly equal counts (quartiles, deciles). Both return a categorical Series you can group by.

Syntax

pd.cut(x, bins, labels=None, right=True, include_lowest=False)   |   pd.qcut(x, q, labels=None, duplicates="raise")
PartWhat it is
binscut: number of equal-width bins or a list of edges
qqcut: number of quantiles, or a list of quantile points like [0, .5, 1]
labelsNames for the bins; False returns integer codes
rightcut: True makes intervals closed on the right, (a, b]
include_lowestcut: include the first edge in the first bin

Examples

import pandas as pd

df = pd.DataFrame({"age": [5, 17, 25, 40, 67]})
df["band"] = pd.cut(df["age"], bins=[0, 17, 64, 120], labels=["child", "adult", "senior"])
df

Result: age band 0 5 child 1 17 child 2 25 adult 3 40 adult 4 67 senior

Edges are right-closed: 17 falls in (0, 17], the child band.

pd.cut(df["age"], bins=[0, 17, 64, 120]).tolist()

Result: [Interval(0, 17, closed='right'), Interval(0, 17, closed='right'), Interval(17, 64, closed='right'), Interval(17, 64, closed='right'), Interval(64, 120, closed='right')]

s = pd.Series([1, 2, 3, 4, 5, 6, 7, 8])
pd.qcut(s, 4, labels=["Q1", "Q2", "Q3", "Q4"]).tolist()

Result: ['Q1', 'Q1', 'Q2', 'Q2', 'Q3', 'Q3', 'Q4', 'Q4']

Quartiles: two values in each bin.

Common mistakes

  • NaN for the smallest value: with right=True the lowest edge is excluded; pass include_lowest=True or start the bins lower.
  • ValueError: Bin edges must be unique in qcut: many repeated values; pass duplicates="drop" or use fewer quantiles.
  • ValueError: Bin labels must be one fewer than the number of bin edges: four edges define three bins, so pass three labels.

Practice cut and qcut

These drills check your answer on live data, free, no account needed.

  • Quartile bins with qcutSplit customers into four groups with equal numbers of customers by `spend`, labeled "Q1" (lowest) to "Q4" (highest). Return the labels as a Series.
  • Age bands with cutLabel each age with a band using the edges 0, 18, 35, 60 and 120 and the labels "child", "young adult", "adult" and "senior". Each band includes its upper edge (18 is a child, 35 is a young adult). Return a Series.

Questions

cut or qcut?

cut when the boundaries have meaning (age bands, price tiers); qcut when you want equal-sized groups like quartiles or deciles regardless of the values.

How do I bin into equal-width intervals automatically?

pd.cut(s, bins=5) splits the range from min to max into five equal-width intervals.

Related

  • value_countsHow to count values in a pandas column with value_counts: counts sorted by frequency, percentages with normalize=True, including NaN, and two-column combos.
  • groupbyHow groupby works in pandas: group by one or more columns, apply sum, mean, count or size, get a flat table with as_index=False, and iterate over groups.
  • rankHow to rank in pandas with rank: ascending or descending, tie methods (average, min, dense, first), ranking within groups, percentile ranks, integer output.
  • applyHow to use apply in pandas on a Series or DataFrame, with axis=1 for row-wise logic, lambdas, returning several columns, and why vectorized code is faster.

Previous: resampleNext: describe