TL;DR: Using a LabelEncoder to encode ordinal any kind of features is a bad idea!


This is in fact clearly stated in the docs, where it is mentioned that as its name suggests this encoding method is aimed at encoding the label:

This transformer should be used to encode target values, i.e. y, and not the input X.

As you rightly point out in the question, mapping the inherent ordinality of an ordinal feature to a wrong scale will have a very negative impact on the performance of the model (that is, proportional to the relevance of the feature). And the same applies to a categorical feature, just that the original feature has no ordinality.

An intuitive way to think about it, is in the way a decision tree sets its boundaries. During training, a decision tree will learn the optimal features to set at each node, as well as an optimal threshold whereby unseen samples will follow a branch or another depending on these values.

If we encode an ordinal feature using a simple LabelEncoder, that could lead to a feature having say 1 represent warm, 2 which maybe would translate to hot, and a 0 representing boiling. In such case, the result will end up being a tree with an unnecessarily high amount of splits, and hence a much higher complexity for what should be simpler to model.

Instead, the right approach would be to use an OrdinalEncoder, and define the appropriate mapping schemes for the ordinal features. Or in the case of having a categorical feature, we should be looking at OneHotEncoder or the various encoders available in Category Encoders.


Though actually seeing why this is a bad idea will be more intuitive than just words.

Let's use a simple example to illustrate the above, consisting on two ordinal features containing a range with the amount of hours spend by a student preparing for an exam and the average grade of all previous assignments, and a target variable indicating whether the exam was past or not. I've defined the dataframe's columns as pd.Categorical:

df = pd.DataFrame(
        {'Hours of dedication': pd.Categorical(
              values =  ['25-30', '20-25', '5-10', '5-10', '40-45', 
                         '0-5', '15-20', '20-25', '30-35', '5-10',
                         '10-15', '45-50', '20-25'],
              categories=['0-5', '5-10', '10-15', '15-20', 
                          '20-25', '25-30','30-35','40-45', '45-50']),

         'Assignments avg grade': pd.Categorical(
             values =  ['B', 'C', 'F', 'C', 'B', 
                        'D', 'C', 'A', 'B', 'B', 
                        'B', 'A', 'D'],
             categories=['F', 'D', 'C', 'B','A']),

         'Result': pd.Categorical(
             values = ['Pass', 'Pass', 'Fail', 'Fail', 'Pass', 
                       'Fail', 'Fail','Pass','Pass', 'Fail', 
                       'Fail', 'Pass', 'Pass'], 
             categories=['Fail', 'Pass'])
        }
    )

The advantage of defining a categorical column as a pandas' categorical, is that we get to establish an order among its categories, as mentioned earlier. This allows for much faster sorting based on the established order rather than lexical sorting. And it can also be used as a simple way to get codes for the different categories according to their order.

So the dataframe we'll be using looks as follows:

print(df.head())

  Hours_of_dedication   Assignments_avg_grade   Result
0               20-25                       B     Pass
1               20-25                       C     Pass
2                5-10                       F     Fail
3                5-10                       C     Fail
4               40-45                       B     Pass
5                 0-5                       D     Fail
6               15-20                       C     Fail
7               20-25                       A     Pass
8               30-35                       B     Pass
9                5-10                       B     Fail

The corresponding category codes can be obtained with:

X = df.apply(lambda x: x.cat.codes)
X.head()

   Hours_of_dedication   Assignments_avg_grade   Result
0                    4                       3        1
1                    4                       2        1
2                    1                       0        0
3                    1                       2        0
4                    7                       3        1
5                    0                       1        0
6                    3                       2        0
7                    4                       4        1
8                    6                       3        1
9                    1                       3        0

Now let's fit a DecisionTreeClassifier, and see what is how the tree has defined the splits:

from sklearn import tree

dt = tree.DecisionTreeClassifier()
y = X.pop('Result')
dt.fit(X, y)

We can visualise the tree structure using plot_tree:

t = tree.plot_tree(dt, 
                   feature_names = X.columns,
                   class_names=["Fail", "Pass"],
                   filled = True,
                   label='all',
                   rounded=True)

Is that all?? Well… yes! I've actually set the features in such a way that there is this simple and obvious relation between the Hours of dedication feature, and whether the exam is passed or not, making it clear that the problem should be very easy to model.


Now let's try to do the same by directly encoding all features with an encoding scheme we could have obtained for instance through a LabelEncoder, so disregarding the actual ordinality of the features, and just assigning a value at random:

df_wrong = df.copy()
df_wrong['Hours_of_dedication'].cat.set_categories(
             ['0-5','40-45', '25-30', '10-15', '5-10', '45-50','15-20', 
              '20-25','30-35'], inplace=True)
df_wrong['Assignments_avg_grade'].cat.set_categories(
             ['A', 'C', 'F', 'D', 'B'], inplace=True)

rcParams['figure.figsize'] = 14,18
X_wrong = df_wrong.drop(['Result'],1).apply(lambda x: x.cat.codes)
y = df_wrong.Result

dt_wrong = tree.DecisionTreeClassifier()
dt_wrong.fit(X_wrong, y)

t = tree.plot_tree(dt_wrong, 
                   feature_names = X_wrong.columns,
                   class_names=["Fail", "Pass"],
                   filled = True,
                   label='all',
                   rounded=True)

As expected the tree structure is way more complex than necessary for the simple problem we're trying to model. In order for the tree to correctly predict all training samples it has expanded until a depth of 4, when a single node should suffice.

This will imply that the classifier is likely to overfit, since we’re drastically increasing the complexity. And by pruning the tree and tuning the necessary parameters to prevent overfitting we are not solving the problem either, since we’ve added too much noise by wrongly encoding the features.

So to summarize, preserving the ordinality of the features once encoding them is crucial, otherwise as made clear with this example we'll lose all their predictable power and just add noise to our model.

Answer from yatu on Stack Overflow
🌐
GeeksforGeeks
geeksforgeeks.org › machine learning › ml-label-encoding-of-datasets-in-python
Label Encoding in Python - GeeksforGeeks
The encoded labels are typically assigned based on the sorted order of unique categories. Produces a compact representation of categorical data using a single feature column. Commonly applied to target variables and ordinal features in machine ...
Published: June 11, 2026
🌐
Great Learning
mygreatlearning.com › blog › ai and machine learning › label encoding in python
What is Label Encoding in Python | Great Learning
December 18, 2024 - In label encoding in Python, we replace the categorical value with a numeric value between 0 and the number of classes minus 1. If the categorical variable value contains 5 distinct classes, we use (0, 1, 2, 3, and 4). To understand label encoding ...
Discussions

python - LabelEncoder for categorical features? - Stack Overflow
This might be a beginner question but I have seen a lot of people using LabelEncoder() to replace categorical variables with ordinality. A lot of people using this feature by passing multiple colum... More on stackoverflow.com
🌐 stackoverflow.com
Label Encoding for categorical columns - xgboost
Did a quick search and did not find where XGBoost documentation suggests to use label encoding for categorical features. On this page they talk about experimental support for categorical features saying that two methods are supported - one-hot encoding and partitioning. BTW, Scikit-Learn documentation recommends not to use label encoder for features. I would probably use one-hot ending for small number of categories, and target encoding, or ordered target encoding (see SatQuest explanaition , implementation ), when number of categories is large. More on reddit.com
🌐 r/datascience
9
3
June 9, 2023
What is your go-to encoding for categorical variables?
One hot if there’s just a few categories. Binary otherwise. I am not adding 156 columns to encode country, even if it sacrifices some accuracy. More on reddit.com
🌐 r/learnmachinelearning
9
5
November 1, 2021
[D] Why one-hot encoding is a poor fit for random forest classifiers and ensembles of weak estimators in general
You might want to read this: https://roamanalytics.com/2016/10/28/are-categorical-variables-getting-lost-in-your-random-forests/ More on reddit.com
🌐 r/MachineLearning
45
157
August 27, 2020
People also ask

Which encoding is best for categorical data?
It depends on the categorical variables. For nominal data with few unique values, one hot encoding is best since it creates clear binary columns and avoids fake ordinal relationships. For ordinal data, where order matters, label encoding is usually better because it keeps the natural order.
🌐
unidata.pro
unidata.pro › home › unidata blog › datasets › encoding categorical variables: one-hot vs. label encoding and beyond
Encoding Categorical Variables: One-Hot vs. Label Encoding and Beyond
What is one hot label encoding?
The term often mixes two ideas. Label encoding assigns a unique integer to each category, while one hot encoding creates new binary columns for those integers as separate features. Some people casually call this one hot label encoding, but technically they are distinct encoding methods.
🌐
unidata.pro
unidata.pro › home › unidata blog › datasets › encoding categorical variables: one-hot vs. label encoding and beyond
Encoding Categorical Variables: One-Hot vs. Label Encoding and Beyond
Should I use a label encoder or one-hot encoding?
Choose based on data type and machine learning algorithms. Label encoding is compact and works with tree based models like decision trees or random forests, which can split on integer codes. One hot encoding is safer for linear regression, logistic regression, or neural nets, since it avoids fake numeric order. If you face high cardinality, consider advanced encoders like target encoding or frequency encoding.
🌐
unidata.pro
unidata.pro › home › unidata blog › datasets › encoding categorical variables: one-hot vs. label encoding and beyond
Encoding Categorical Variables: One-Hot vs. Label Encoding and Beyond
🌐
Unidata
unidata.pro › home › unidata blog › datasets › encoding categorical variables: one-hot vs. label encoding and beyond
Encoding Categorical Variables: One-Hot vs. Label Encoding and Beyond
March 4, 2026 - That’s why we encode categorical variables into numbers the model can learn from. The encoding method changes how models read your data. Label encoding assigns an integer value to each class.
Top answer
1 of 1
28

TL;DR: Using a LabelEncoder to encode ordinal any kind of features is a bad idea!


This is in fact clearly stated in the docs, where it is mentioned that as its name suggests this encoding method is aimed at encoding the label:

This transformer should be used to encode target values, i.e. y, and not the input X.

As you rightly point out in the question, mapping the inherent ordinality of an ordinal feature to a wrong scale will have a very negative impact on the performance of the model (that is, proportional to the relevance of the feature). And the same applies to a categorical feature, just that the original feature has no ordinality.

An intuitive way to think about it, is in the way a decision tree sets its boundaries. During training, a decision tree will learn the optimal features to set at each node, as well as an optimal threshold whereby unseen samples will follow a branch or another depending on these values.

If we encode an ordinal feature using a simple LabelEncoder, that could lead to a feature having say 1 represent warm, 2 which maybe would translate to hot, and a 0 representing boiling. In such case, the result will end up being a tree with an unnecessarily high amount of splits, and hence a much higher complexity for what should be simpler to model.

Instead, the right approach would be to use an OrdinalEncoder, and define the appropriate mapping schemes for the ordinal features. Or in the case of having a categorical feature, we should be looking at OneHotEncoder or the various encoders available in Category Encoders.


Though actually seeing why this is a bad idea will be more intuitive than just words.

Let's use a simple example to illustrate the above, consisting on two ordinal features containing a range with the amount of hours spend by a student preparing for an exam and the average grade of all previous assignments, and a target variable indicating whether the exam was past or not. I've defined the dataframe's columns as pd.Categorical:

df = pd.DataFrame(
        {'Hours of dedication': pd.Categorical(
              values =  ['25-30', '20-25', '5-10', '5-10', '40-45', 
                         '0-5', '15-20', '20-25', '30-35', '5-10',
                         '10-15', '45-50', '20-25'],
              categories=['0-5', '5-10', '10-15', '15-20', 
                          '20-25', '25-30','30-35','40-45', '45-50']),

         'Assignments avg grade': pd.Categorical(
             values =  ['B', 'C', 'F', 'C', 'B', 
                        'D', 'C', 'A', 'B', 'B', 
                        'B', 'A', 'D'],
             categories=['F', 'D', 'C', 'B','A']),

         'Result': pd.Categorical(
             values = ['Pass', 'Pass', 'Fail', 'Fail', 'Pass', 
                       'Fail', 'Fail','Pass','Pass', 'Fail', 
                       'Fail', 'Pass', 'Pass'], 
             categories=['Fail', 'Pass'])
        }
    )

The advantage of defining a categorical column as a pandas' categorical, is that we get to establish an order among its categories, as mentioned earlier. This allows for much faster sorting based on the established order rather than lexical sorting. And it can also be used as a simple way to get codes for the different categories according to their order.

So the dataframe we'll be using looks as follows:

print(df.head())

  Hours_of_dedication   Assignments_avg_grade   Result
0               20-25                       B     Pass
1               20-25                       C     Pass
2                5-10                       F     Fail
3                5-10                       C     Fail
4               40-45                       B     Pass
5                 0-5                       D     Fail
6               15-20                       C     Fail
7               20-25                       A     Pass
8               30-35                       B     Pass
9                5-10                       B     Fail

The corresponding category codes can be obtained with:

X = df.apply(lambda x: x.cat.codes)
X.head()

   Hours_of_dedication   Assignments_avg_grade   Result
0                    4                       3        1
1                    4                       2        1
2                    1                       0        0
3                    1                       2        0
4                    7                       3        1
5                    0                       1        0
6                    3                       2        0
7                    4                       4        1
8                    6                       3        1
9                    1                       3        0

Now let's fit a DecisionTreeClassifier, and see what is how the tree has defined the splits:

from sklearn import tree

dt = tree.DecisionTreeClassifier()
y = X.pop('Result')
dt.fit(X, y)

We can visualise the tree structure using plot_tree:

t = tree.plot_tree(dt, 
                   feature_names = X.columns,
                   class_names=["Fail", "Pass"],
                   filled = True,
                   label='all',
                   rounded=True)

Is that all?? Well… yes! I've actually set the features in such a way that there is this simple and obvious relation between the Hours of dedication feature, and whether the exam is passed or not, making it clear that the problem should be very easy to model.


Now let's try to do the same by directly encoding all features with an encoding scheme we could have obtained for instance through a LabelEncoder, so disregarding the actual ordinality of the features, and just assigning a value at random:

df_wrong = df.copy()
df_wrong['Hours_of_dedication'].cat.set_categories(
             ['0-5','40-45', '25-30', '10-15', '5-10', '45-50','15-20', 
              '20-25','30-35'], inplace=True)
df_wrong['Assignments_avg_grade'].cat.set_categories(
             ['A', 'C', 'F', 'D', 'B'], inplace=True)

rcParams['figure.figsize'] = 14,18
X_wrong = df_wrong.drop(['Result'],1).apply(lambda x: x.cat.codes)
y = df_wrong.Result

dt_wrong = tree.DecisionTreeClassifier()
dt_wrong.fit(X_wrong, y)

t = tree.plot_tree(dt_wrong, 
                   feature_names = X_wrong.columns,
                   class_names=["Fail", "Pass"],
                   filled = True,
                   label='all',
                   rounded=True)

As expected the tree structure is way more complex than necessary for the simple problem we're trying to model. In order for the tree to correctly predict all training samples it has expanded until a depth of 4, when a single node should suffice.

This will imply that the classifier is likely to overfit, since we’re drastically increasing the complexity. And by pruning the tree and tuning the necessary parameters to prevent overfitting we are not solving the problem either, since we’ve added too much noise by wrongly encoding the features.

So to summarize, preserving the ordinality of the features once encoding them is crucial, otherwise as made clear with this example we'll lose all their predictable power and just add noise to our model.

🌐
Medium
medium.com › @sunnykumar1516 › what-is-label-encoding-application-of-label-encoder-in-machine-learning-and-deep-learning-models-c593669483ed
label encoding. what is label encoding. label encoding in machine learning. sklearn label encoding . python label encoding. python label encoder | Medium
January 12, 2024 - Label encoding is a process in machine learning where categorical data, represented as labels or strings, is converted into numerical format. In this encoding technique, each unique category is assigned a unique integer, effectively converting ...
Find elsewhere
🌐
Towards Data Science
towardsdatascience.com › home › latest › encoding categorical data, explained: a visual guide with code example for beginners
Encoding Categorical Data, Explained: A Visual Guide with Code Example for Beginners | Towards Data Science
January 13, 2025 - Label Encoding assigns a unique integer to each category in a categorical variable. Common Use 👍 : It's often used for ordinal variables where there's a clear order to the categories, such as education levels (e.g., primary, secondary, tertiary) ...
🌐
Kaggle
kaggle.com › getting-started › 419313
🎯 Understanding Label Encoding 🎯 | Kaggle
import numpy as np from ... data print(encoded_data) ... Label encoding is a simple and effective way to convert categorical variables into numerical format....
🌐
Saturn Cloud
saturncloud.io › glossary › label-encoding
Label Encoding | Saturn Cloud
April 4, 2023 - Label encoding is a process of assigning numerical labels to categorical data values. It is a simple and efficient way to convert categorical data into numerical data that can be used for analysis and modelling.
🌐
CodeSignal
codesignal.com › learn › courses › shaping-and-transforming-features › lessons › encoding-categorical-data-a-practical-approach
Categorical Data Encoding Techniques | CodeSignal Learn
One-Hot Encoding transforms each ... three columns: red, green, and blue, with a '1' in the appropriate column. Label Encoding assigns a unique integer to each category value....
🌐
Medium
medium.com › @abdurahmanridwan02 › exploring-categorical-data-encoding-label-encoding-vs-one-hot-encoding-318c619794b
Exploring Categorical Data Encoding: Label Encoding vs. One-Hot Encoding | by Ridwan Abdurahman | Medium
September 26, 2023 - Label Encoding is a straightforward method that assigns a unique integer to each category in a categorical variable. For example, if we have a "City" column with values "New York," "Los Angeles," and "Chicago," Label Encoding will convert them ...
🌐
Analytics Vidhya
analyticsvidhya.com › home › how to perform label encoding in python?
Label Encoding in Python Explained with Examples
December 19, 2023 - Clustering Analysis: Label encoding can be utilized in clustering analysis, where categorical variables must be transformed into numerical labels for clustering algorithms to identify patterns and groups within the data.
🌐
GeeksforGeeks
geeksforgeeks.org › machine learning › categorical-data-encoding-techniques-in-machine-learning
Categorical Data Encoding Techniques in Machine Learning - GeeksforGeeks
September 18, 2025 - Encoding Options: One-Hot Encoding or Label Encoding, depending on the model's needs. 2. Ordinal Data: Ordinal data includes categories with a defined order or ranking, where the relationship between values is important. Example: 'Low', 'Medium', 'High' (Car Engine Power). Encoding Options: Ordinal Encoding. Using the right encoding techniques, we can effectively transform categorical data for machine learning models which improves their performance and predictive capabilities.
🌐
Analytics Vidhya
analyticsvidhya.com › home › one hot encoding vs label encoding in machine learning
One Hot Encoding vs Label Encoding in Machine Learning
April 23, 2025 - Checkout our course on Applied Machine Learning – Beginner to Professional to know everything about ML functions! Label Encoding is a common technique for converting categorical variables into numerical values.
🌐
Medium
medium.com › @vipinnation › unraveling-categorical-variables-understanding-label-ordinal-and-one-hot-encoding-techniques-8f5375151fed
Unraveling Categorical Variables: Understanding Label, Ordinal, and One-Hot Encoding Techniques | by Vipin Singh Inkiya | Medium
April 20, 2024 - Label Encoding assigns a unique integer value to each category in a categorical variable. Let’s say we have a dataset containing information about car colors: Red, Green, and Blue. from sklearn.preprocessing import LabelEncoder # Sample data ...
🌐
Micheledpierri
micheledpierri.com › home › machine learning › encoding of categorical variables
Encoding of Categorical Variables
November 8, 2025 - The LabelEncoder function transforms categorical variables by assigning a unique number to each category. For example, let’s consider a “color” variable that we want to convert into a numeric format. from sklearn.preprocessing import ...
🌐
AI ML Analytics
ai-ml-analytics.com › home › categorical encoding using label encoding
Categorical Encoding using Label Encoding
December 13, 2024 - Label Encoding is a technique of converting the labels into numeric form so that it could be ingested to a machine learning model.In Label Encoding, we generally replace each value in a categorical column with numbers from 0 to N-1.
🌐
DataCamp
datacamp.com › datalab › templates › recipe-python-encoding-categorical-variables
Free Template: Encoding Categorical Variables | DataLab
Use feature engineering techniques such as one-hot encoding and label encoding to pre-process categorical data for use in machine learning algorithms.
🌐
Feaz-book
feaz-book.com › categorical-label
Feature Engineering A-Z | Label Encoding – Feature Engineering A-Z
Label encoding (also called integer encoding) is a method that maps the categorical levels into the integers 1 through n where n is the number of levels.