将分类数据传递给 Sklearn 决策树

Passing categorical data to Sklearn Decision Tree

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

Some advantages of decision trees are:

(...)

Able to handle both numerical and categorical data. Other techniques are usually specialized in analyzing datasets that have only one type of variable. See the algorithms for more information.

但是运行下面的脚本

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 传递分类数据,这可能吗?

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 提供的工具。这样做的主要原因是它们可以很容易地集成到 Pipeline.

Scikit-Learn 本身提供了非常好的 classes 来处理分类数据。您应该使用 专门为此目的设计的 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]))

这会 return ['tokyo', 'tokyo', 'paris']

另请注意,对于许多其他 class 化器,除了逻辑回归或 SVM 等决策树之外,您还想使用 One-Hot encoding. Scikit-learn supports this as well through the OneHotEncoder class 对分类变量进行编码。

希望对您有所帮助!

(..)

Able to handle both numerical and categorical data.

这仅表示您可以使用

  • DecisionTreeClassifier class class化问题
  • 用于回归的 DecisionTreeRegressor class。

在任何情况下,您都需要在使用 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'])

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

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

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

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

使用 OneHotEncoder 是当前唯一有效的方法,允许任意拆分而不依赖于标签顺序,但计算量大。

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

截至 v0.24.0, scikit supports the use of categorical features in HistGradientBoostingClassifier and HistGradientBoostingRegressor natively!

To enable categorical support, a boolean mask can be passed to the categorical_features parameter, indicating which feature is categorical. In the following, the first feature will be treated as categorical and the second feature as numerical:

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

Equivalently, one can pass a list of integers indicating the indices of the categorical features:

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

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

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

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

有关详细信息,请参阅此 URL: https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html