gpt4 book ai didi

python - 用于分类功能的LabelEncoder?

转载 作者:行者123 更新时间:2023-12-03 15:21:18 26 4
gpt4 key购买 nike

这可能是一个初学者的问题,但是我已经看到很多人使用LabelEncoder()用常规替换类别变量。很多人一次通过传递多列来使用此功能,但是我对某些功能中的错误序数及其对模型的影响会产生疑问。这是一个例子:

输入

import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder

a = pd.DataFrame(['High','Low','Low','Medium'])
le = LabelEncoder()
le.fit_transform(a)

输出
array([0, 1, 1, 2], dtype=int64)

如您所见,序数值未正确映射,因为我的LabelEncoder仅关心列/数组中的顺序(应该为High = 1,Med = 2,Low = 3,反之亦然)。错误的严重映射会如何影响模型?除了OrdinalEncoder()之外,还有其他简便的方法可以正确映射这些值吗?

最佳答案

TL; DR :使用 LabelEncoder 对任何类型的特征进行序数编码是一个坏主意!

实际上,这在文档中有明确说明,其中提到,顾名思义,该编码方法旨在对标签进行编码:

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


正如您在问题中正确指出的那样,将 ordinal feature的固有序数映射到错误的比例将对模型的性能产生非常负面的影响(即与特征的相关性成比例)。同样, categorical feature也是如此,只是原始特征没有序数。
一种思考的直观方式是 decision tree设置其边界。在训练过程中,决策树将学习要在每个节点上设置的最佳功能以及最佳阈值,根据这些值,看不见的样本将沿着一个分支或另一个分支前进。
如果我们使用简单的 LabelEncoder编码序数特征,则可能会导致某个特征说 1表示温暖, 2可能转换为热,而 0表示沸腾。在这种情况下,结果最终将是一棵不必要的大量拆分树,因此,对于更简单的建模而言,其复杂性将大大提高。
相反,正确的方法是使用 OrdinalEncoder ,并为序数特征定义适当的映射方案。或在具有分类功能的情况下,我们应该查看 OneHotEncoder Category Encoders中可用的各种编码器。

尽管实际上了解到为什么这是一个坏主意,将比仅凭文字更直观。
让我们使用一个简单的示例来说明上述内容,该示例由两个序数功能组成,其中包含一个范围,该范围包括学生准备考试的时数和所有以前作业的平均成绩,以及一个目标变量,指示考试是否已过或不。我已经将数据框的列定义为 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'])
}
)
如前所述,将类别列定义为 Pandas 的类别的好处是我们可以在其类别之间建立顺序。这允许基于已建立的顺序而不是词法排序更快地进行排序。它也可以用作一种简单的方法来根据其顺序获取不同类别的代码。
因此,我们将使用的数据帧如下所示:
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
可以通过以下方式获得相应的类别代码:
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
现在,让我们拟合 DecisionTreeClassifier ,看看树如何定义拆分:
from sklearn import tree

dt = tree.DecisionTreeClassifier()
y = X.pop('Result')
dt.fit(X, y)
我们可以使用 plot_tree 可视化树结构:
t = tree.plot_tree(dt, 
feature_names = X.columns,
class_names=["Fail", "Pass"],
filled = True,
label='all',
rounded=True)
enter image description here
这就是全部??好吧... 是的! 我实际上已经以某种方式设置功能,使得“奉献时数”功能与是否通过考试之间存在这种简单而明显的关系,这清楚地表明,该问题应该非常容易建模。

现在,让我们尝试通过使用我们可以通过 LabelEncoder获得的编码方案直接编码所有特征来进行相同操作,因此不考虑特征的实际顺序,而只是随机分配一个值:
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)
enter image description here
不出所料,树结构比我们要建模的简单问题复杂得多。为了使树正确地预测所有训练样本,它已扩展到单个节点就足够的 4深度为止。
这意味着分类器可能会过拟合,因为我们正在极大地增加复杂性。通过修剪树并调整必要的参数以防止过度拟合,我们也无法解决问题,因为我们通过错误地编码特征而添加了过多噪声。
因此,总而言之,一旦对特征进行编码,保留特征的普遍性至关重要,否则如本例所示,我们将失去其所有可预测的功能,而只会给模型增加噪声。

关于python - 用于分类功能的LabelEncoder?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61217713/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com