All You Need to Know About Pandas Cut and Qcut Functions | by Soner Yıldırım | Towards Data Science

Pandas is arguably the most popular data analysis and manipulation tool in the data science ecosystem. Thanks to the numerous functions and methods, we can play around with data freely.
The cut and qcut functions come in quite handy for many cases. The difference between them was not clear to me at first. I was able to figure it out after doing several examples.
In this article, we will do the same. The examples in this article will demonstrate how to use the cut and qcut functions and also emphasize the difference between them.
Let’s start with creating a sample data frame.
import numpy as npimport pandas as pddf = pd.DataFrame({  "col_a": np.random.randint(1, 50, size=50),  "col_b": np.random.randint(20, 100, size=50),  "col_c": np.random.random(size=50).round(2)})df.head()
The first and second columns contain integers between 1-50 and 20–100, respectively. The third column contains floats between 0 and 1. We have used numpy functions to generate these values randomly.
The cut function divides the entire value range into bins. The range covered by each bin will be the same.
In the first column (col_a), we randomly assign integers between 1 and 50. Let’s first check the minimum and maximum values in this column.
df.col_a.max(), df.col_a.min()(49, 3)
If you want to divide this column into 5 bins of equal range, the size of each bin will be 9.2 which can be calculated as follows:
(49 - 3) / 5 = 9.2
The cut function performs this binning operation and then assign each value in the appropriate bin.
df["col_a_binned"] = pd.cut(df.col_a, bins=5)df.col_a_binned.value_counts()(21.4, 30.6]     16 (39.8, 49.0]     14 (12.2, 21.4]      8 (30.6, 39.8]      6 (2.954, 12.2]     6
As we can see, the size of each bin is exactly 9.2 expect for the smallest one. The lower bounds are not inclusive. Thus, the lower bound of the smallest bin is a little less than the smallest value (3) to be able to include it.
We can customize the bins by defining the bin edges manually. The edge values are passed to the bins parameter as a list.
pd.cut(df.col_a, bins=[0, 10, 40, 50]).value_counts()(10, 40]    33 (40, 50]    13 (0, 10]      4
The right edges are inclusive by default but it can be changed.
pd.cut(df.col_a, bins=[0, 10, 40, 50], right=False).value_counts()[10, 40)    33 [40, 50)    13 [0, 10)      4
With the cut function, we do not have any control over how many values fall into each bin. We can only specify the bin edges.
This is where we need to learn about the qcut function. It can be used to divide the values into buckets in a way that each bucket contains approximately the same number of values.
Let’s start with an example.
pd.qcut(df.col_a, q=4).value_counts()(40.75, 49.0]    13 (19.5, 25.0]     13 (2.999, 19.5]    13 (25.0, 40.75]    11
We have 4 buckets and each one contains almost the same number of values. In case of 4, the buckets are also called quartiles. One quarter of the total number of values are in the first quartile, one half are in the first two buckets, and so on.
With the qcut function, we do not have any control over the bin edges. They are calculated automatically. Consider there are 40 values (i.e. rows) in a column and we want to have 4 buckets. Starting from the smallest value, the upper range of the first bucket will be determined in a way that the first bucket contains 10 values.
Cut function: The focus is on the size of bins in terms of the value range (i.e. the difference between the upper and lower bin edges)
Qcut function: The focus is on the size of bins in terms of the number of values in each bin.
The qcut function allows for customizing the bucket sizes. Let’s create 3 buckets. The first one contains the smallest 50 percent of values (i.e. lower half). Then, we divide the upper half into two bins.
pd.qcut(df.col_a, q=[0, .50, .75, 1]).value_counts()(2.999, 25.0]    26 (40.75, 49.0]    13 (25.0, 40.75]    11
Both the cut and qcut functions allow for labelling the bins or buckets. We use the labels parameter as follows.
df["new"] = pd.qcut(df.col_a, q=[0, .33, .66, 1], labels=["small", "medium", "high"])df["new"].value_counts()high      17 small     17 medium    16
It is like converting a continuous variable into a categorial one. Let’s check the average of values in each category to make sure qcut function has worked properly.
df.groupby("new").agg(avg=("col_a","mean"))               avgnewsmall    14.000000medium   26.687500high     43.705882
The average increase as we go from small to high which is expected.
Both the cut and qcut functions can be used to convert a set of continuous values into a discrete or categorical variable.
The cut function focuses on the value range of bins. It determines the entire range based on the difference between the smallest and largest values. Then, it divides the entire range into bins based on the desired number of bins. By default, the size of each bin is the same (approximately) and it is the difference between the lower and upper bin edge.
The qcut function focuses on the number of values in each bin. The values are sorted from the smallest to largest. If we want 5 buckets, the first 20 percent of values are placed in the first bucket, the second 20 percent are placed in the second bucket, and so on.
Both these functions allow for customizing the upper and lower edges. Thus, we can have bins or buckets with different sizes.
Thank you for reading. Please let me know if you have any feedback.