使用OrdinalEncoder转换分类值

22

我有一个数据集,其中包含以下列:

No  Name  Sex  Blood  Grade  Height  Study
1   Tom   M    O      56     160     Math
2   Harry M    A      76     192     Math
3   John  M    A      45     178     English
4   Nancy F    B      78     157     Biology
5   Mike  M    O      79     167     Math
6   Kate  F    AB     66     156     English
7   Mary  F    O      99     166     Science

我希望您能把它改成这样:

No  Name  Sex  Blood  Grade  Height  Study
1   Tom   0    0      56     160     0
2   Harry 0    1      76     192     0
3   John  0    1      45     178     1
4   Nancy 1    2      78     157     2
5   Mike  0    0      79     167     0
6   Kate  1    3      66     156     1
7   Mary  0    0      99     166     3

我知道有一個可以做到這件事的程式庫。

from sklearn.preprocessing import OrdinalEncoder

我尝试过这个,但它没有起作用。

enc = OrdinalEncoder()
enc.fit(df[["Sex","Blood", "Study"]])

有谁能帮我找出我做错了什么以及如何做吗?

5个回答

44

你差一点就成功了!

基本上,fit方法是为编码器准备数据(即准备映射关系),但不会转换数据。

你需要调用transform来转换数据,或者使用fit_transform方法,该方法会同时拟合和转换相同的数据。

enc = OrdinalEncoder()
enc.fit(df[["Sex","Blood", "Study"]])
df[["Sex","Blood", "Study"]] = enc.transform(df[["Sex","Blood", "Study"]])

或者直接

enc = OrdinalEncoder()
df[["Sex","Blood", "Study"]] = enc.fit_transform(df[["Sex","Blood", "Study"]])

注意:由于拟合方法内部使用了 numpy.unique ,该方法返回按字母顺序排序的结果,而不是按出现顺序排序,因此返回的值可能与提供的值不同。

enc.categories_ 中可以看到。

[array(['F', 'M'], dtype=object),
 array(['A', 'AB', 'B', 'O'], dtype=object),
 array(['Biology', 'English', 'Math', 'Science'], dtype=object)]```

数组中的每个值的编码都由其位置确定。(F将被编码为0,M将被编码为1)


运行该行代码后仍然出现Male/Female而非0/1,无法正常工作!!! - asmgx
很奇怪,就像你看到的那样,它在我的电脑上可以工作。 - abcdaire
你找到答案了吗?也许问题存在是因为你使用的数据框不是原始数据框,而是一个切片? - abcdaire

30
我认为需要指出的是,这不是变量的序数编码示例。性别、血型和学习都不应该具有序数尺度(提问者也没有建议这样做)。序数数据具有排名(例如,请参见https://en.wikipedia.org/wiki/Ordinal_data),这些示例没有排名。
如果您的变量是目标变量,则可以使用LabelEncoder。(https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html
然后,您可以执行以下操作:
from sklearn.preprocessing import LabelEncoder

for col in ["Sex","Blood", "Study"]:
    df[col] = LabelEncoder().fit_transform(df[col])

如果您的变量是特征,应该使用Ordinalencoder来实现。 (请参见对我的答案的评论)。
Ordinalencoder的命名非常不幸,因为“ordinal”是从数学而不是统计的角度命名的。
有关sklearn中ordinal编码器和标签编码器之间的区别的更多信息:https://datascience.stackexchange.com/questions/39317/difference-between-ordinalencoder-and-labelencoder

5
你说得有道理,但重要的是要注意,我认为LabelEncoder在管道中工作得并不好。从我在网上搜集到的信息来看,它仅适用于目标变量或响应变量。因此,为了实现OP想要的功能,他们实际上建议使用OrdinalEncoder。 - Josh
谢谢您的评论。您能否请提供任何资源来支持您的论点?我也不明白您的意思。我很愿意学习 :) - Createdd
1
当然,在用户指南的顶部非常明确地说明了这仅用于转换目标而不是编码特征:https://scikit-learn.org/stable/modules/preprocessing_targets.html#preprocessing-targets您还可以在此GitHub问题响应中看到这一点的回应:https://github.com/scikit-learn/scikit-learn/issues/12720 - Josh
1
你说得对。我认为问题在于使用了“序数”这个词,它并不是从统计学的角度来看待,而是从数学的角度来看待(https://en.wikipedia.org/wiki/Ordinal_number)。我会编辑我的回答。感谢你指出这一点! - Createdd

2

@Createdd是正确的。虽然“性别”,“血型”和“学科”都是分类属性,但有两种分类属性:序数和名义上的。

如果您对名义属性使用OrdinalImputer,则大多数机器学习模型将做出以下假设:数学(0)<英语(1)<生物学(2)<科学(3)。但实际上这不应该是这种情况:“英语”没有处于“数学”和“生物学”之间或任何其他顺序中。一个真正的序数属性应该是像评级这样的东西:“非常差”(0),“差”(1),“中立”(2),“好”(3),“非常好”(4)。

正确的答案应该是对“性别”,“血型”和“学科”属性使用OneHotEncoder(因为它们是名义属性)。


1

这是我的观点:

首先创建编码器:

enc = OrdinalEncoder()

需要转换值的列名称为:
性别、血型、学业
使用 enc.fit_transform() 来拟合并将每列的值转换为下面所示的数字:
X_enc = enc.fit_transform(df["Sex", "Blood", "Study"])

最后,用这些转换后的值替换原始值(即主数据框中的值):
df["Sex", "Blood", "Study"] = pd.DataFrame(X_enc, columns=["Sex", "Blood", "Study"])

答案:

No  Name   Sex  Blood  Grade  Height  Study
1   Tom    1.0  3.0    56     160     2.0
2   Harry  1.0  0.0    76     192     2.0
3   John   1.0  0.0    45     178     1.0
4   Nancy  0.0  2.0    78     157     0.0
5   Mike   1.0  3.0    79     167     2.0
6   Kate   0.0  1.0    66     156     1.0
7   Mary   0.0  3.0    99     166     3.0

1

这里有一个简单的示例,使用sklearn在数据框上应用序数编码。

import pandas as pd

df = pd.DataFrame(
    {
        "gender": ["man", "women", "child", "man", "women", "child"],
        "age": [40, 40, 10, 50, 50, 8],
    }
)


def ordinal_encoding(genders):
    le = LabelEncoder()
    le.fit(genders)
    return le.transform(genders)


encoded_genders = ordinal_encoding(df["gender"])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接