【问题标题】:Passing categorical data to Sklearn Decision Tree将分类数据传递给 Sklearn 决策树
【发布时间】:2016-11-01 16:57:31
【问题描述】:

有几篇关于如何将分类数据编码到 Sklearn 决策树的帖子,但是从 Sklearn 文档中,我们得到了这些

决策树的一些优点是:

(...)

能够处理数字和分类数据。其他技术通常专门用于分析只有一种类型变量的数据集。有关详细信息,请参阅算法。

但运行以下脚本

import pandas as pd 
from sklearn.tree import DecisionTreeClassifier

data = pd.DataFrame()
data['A'] = ['a','a','b','a']
data['B'] = ['b','b','a','b']
data['C'] = [0, 0, 1, 0]
data['Class'] = ['n','n','y','n']

tree = DecisionTreeClassifier()
tree.fit(data[['A','B','C']], data['Class'])

输出如下错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/sklearn/tree/tree.py", line 154, in fit
    X = check_array(X, dtype=DTYPE, accept_sparse="csc")
  File "/usr/local/lib/python2.7/site-packages/sklearn/utils/validation.py", line 377, in check_array
    array = np.array(array, dtype=dtype, order=order, copy=copy)
ValueError: could not convert string to float: b

我知道在 R 中可以通过 Sklearn 传递分类数据,这可能吗?

【问题讨论】:

    标签: python scikit-learn decision-tree


    【解决方案1】:

    Sklearn 决策树不处理分类字符串到数字的转换。我建议你在 Sklearn 中找到一个函数(可能是 this),或者手动编写一些代码,例如:

    def cat2int(column):
        vals = list(set(column))
        for i, string in enumerate(column):
            column[i] = vals.index(string)
        return column
    

    【讨论】:

    • 是的,这是通常的做法,但对于打印来说并不是很好。
    • 如果你想从整数返回到字符串表示,制作一个字典来保存字符串和整数之间的映射,并使用它来“解码”整数表示。
    • 声明不准确。 Scikit-learn 分类器不会隐式处理标签编码。然而,Scikit-learn 提供了很多类来处理这个问题。我建议使用 scikit 学习工具,因为它们也可以轻松融入机器学习管道。
    【解决方案2】:

    与接受的答案相反,我更愿意为此目的使用 Scikit-Learn 提供的工具。这样做的主要原因是它们可以很容易地集成到 Pipeline 中。

    Scikit-Learn 本身提供了非常好的类来处理分类数据。您应该使用LabelEncoder,而不是编写您的自定义函数,它是专门为此目的设计的

    参考文档中的以下代码:

    from sklearn import preprocessing
    le = preprocessing.LabelEncoder()
    le.fit(["paris", "paris", "tokyo", "amsterdam"])
    le.transform(["tokyo", "tokyo", "paris"]) 
    

    这会自动将它们编码为机器学习算法的数字。现在这也支持从整数返回字符串。您可以通过简单地调用inverse_transform 来做到这一点,如下所示:

    list(le.inverse_transform([2, 2, 1]))
    

    这将返回['tokyo', 'tokyo', 'paris']

    另请注意,对于许多其他分类器,除了决策树(例如逻辑回归或 SVM),您希望使用 One-Hot encoding 对分类变量进行编码。 Scikit-learn 也通过 OneHotEncoder 类支持这一点。

    希望这会有所帮助!

    【讨论】:

    • -1 这是误导。就目前而言,sklearn 决策树不处理分类数据 - see issue #5442。这种使用标签编码的方法转换为整数,DecisionTreeClassifier() 将视为数字。如果您的分类数据不是有序的,那就不好了 - 您最终会得到没有意义的拆分。使用OneHotEncoder 是当前唯一有效的方法,但计算量很大。
    • 这是高度误导。请不要将字符串转换为数字并在决策树中使用。在 scikit-learn 中无法处理分类数据。一种选择是使用 Spark 中的决策树分类器——您可以在其中明确声明分类特征及其序数。请参阅此处了解更多详情github.com/scikit-learn/scikit-learn/pull/4899
    • 每个人都必须学习测量尺度,即名义、有序、间隔和比率尺度。数字并不意味着它是名义规模的数字;它只是一面旗帜。例如,我们可以使用 1 代表红色,2 代表蓝色,3 代表绿色。假设 10 个人喜欢红色,10 个人喜欢绿色。计算平均值 ((10*1+10*3)/20 = 2) 并声明平均偏好蓝色是否有意义??
    • 呃...我不知道它有这么多的关注。干杯@ayorgo,会的!
    • 这就是为什么我的实习生不知道如何处理分类变量的原因。
    【解决方案3】:

    (..)

    能够处理数字和分类数据。

    这只表示你可以使用

    • 用于分类问题的 DecisionTreeClassifier 类
    • 用于回归的 DecisionTreeRegressor 类。

    在任何情况下,您都需要在使用 sklearn 拟合树之前对分类变量进行一次热编码,如下所示:

    import pandas as pd
    from sklearn.tree import DecisionTreeClassifier
    
    data = pd.DataFrame()
    data['A'] = ['a','a','b','a']
    data['B'] = ['b','b','a','b']
    data['C'] = [0, 0, 1, 0]
    data['Class'] = ['n','n','y','n']
    
    tree = DecisionTreeClassifier()
    
    one_hot_data = pd.get_dummies(data[['A','B','C']],drop_first=True)
    tree.fit(one_hot_data, data['Class'])
    

    【讨论】:

    • 您可能想玩弄 'pd.get_dummies' ,例如选项 'drop_first = True' 可以帮助避免多重共线性问题。 Here 有一个很好的教程。
    【解决方案4】:

    (这只是对 2016 年 my comment above 的重新格式化......它仍然适用。)

    这个问题的公认答案具有误导性。

    目前,sklearn 决策树不处理分类数据 - see issue #5442

    使用标签编码的推荐方法转换为整数,DecisionTreeClassifier() 会将其视为数字。如果您的分类数据不是序数,这不好 - 您最终会得到没有意义的拆分。

    使用OneHotEncoder 是当前唯一有效的方法,允许任意拆分不依赖于标签排序,但计算成本很高。

    【讨论】:

    • OneHotEncoding 会明显降低决策树的性能,因为它会导致极其稀疏的特征,这会混淆特征重要性roamanalytics.com/2016/10/28/…
    • 同意 - 我不推荐这种方法,但这是避免我目前描述的问题的唯一方法。
    • 我怀疑在某些情况下(具有许多小级别的特征),在有序编码的分类特征上的“废话”分裂仍然比单热编码的非常有限的分裂产生更好的性能功能。
    • 是否有其他的决策树分类器可以处理这个问题?
    • 更新:此 Pull Request(以及其中的讨论)可能会引起您的兴趣:github.com/scikit-learn/scikit-learn/pull/12866
    【解决方案5】:

    对于名义分类变量,我不会使用LabelEncoder,而是使用sklearn.preprocessing.OneHotEncoderpandas.get_dummies,因为这些类型的变量通常没有顺序。

    【讨论】:

      【解决方案6】:

      截至v0.24.0,scikit 支持在HistGradientBoostingClassifierHistGradientBoostingRegressor 中使用分类特征natively

      要启用分类支持,可以将布尔掩码传递给 categorical_features 参数,指示哪个特征是分类的。在下文中,第一个特征将被视为分类特征,第二个特征被视为数字特征:

      >>> gbdt = HistGradientBoostingClassifier(categorical_features=[True, False])
      

      同样,可以传递一个整数列表,指示分类特征的索引:

      >>> gbdt = HistGradientBoostingClassifier(categorical_features=[0])
      

      您仍然需要对字符串进行编码,否则您将收到“无法将字符串转换为浮点数”错误。有关使用 OrdinalEncoder 将字符串转换为整数的示例,请参阅 here

      【讨论】:

      • 抱歉这个无知的问题,但这与决策树有关吗?如果是这样,您能否提供一个示例,说明我们现在如何在决策树中使用分类变量(我是菜鸟……)?
      • 这是梯度提升。 OP 要求提供决策树。
      【解决方案7】:

      是的,决策树能够处理数字和分类数据。 这适用于理论部分,但在实施过程中,您应该在尝试训练或测试模型之前尝试OrdinalEncoderone-hot-encoding 的分类特征。永远记住,机器学习模型除了数字之外什么都不懂。

      【讨论】:

      • ML 模型也不懂英语。
      【解决方案8】:

      您可以应用一些转换方法,例如one hot encoding,将您的分类数据转换为数字实体,然后创建树

      请参阅此网址了解更多信息: https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html

      【讨论】:

        猜你喜欢
        • 2018-10-15
        • 2023-03-29
        • 2018-06-23
        • 2017-10-05
        • 2019-03-04
        • 2018-08-14
        • 2020-10-11
        • 2018-09-15
        • 2020-10-23
        相关资源
        最近更新 更多