使用dtreeviz可视化决策树。

7

我喜欢Dtreeviz库 - GitHub提供的决策树可视化,可以使用它来复制

# Install libraries
!pip install dtreeviz
!apt-get install graphviz

# Sample code
from sklearn.datasets import *
from sklearn import tree
from dtreeviz.trees import *
from IPython.core.display import display, HTML

classifier = tree.DecisionTreeClassifier(max_depth=4)
cancer = load_breast_cancer()

classifier.fit(cancer.data, cancer.target)
viz = dtreeviz(classifier,
               cancer.data,
               cancer.target,
               target_name='cancer',
               feature_names=cancer.feature_names, 
               class_names=["malignant", "benign"],
               fancy=False) 

display(HTML(viz.svg()))

然而,当我将上述方法应用于我自己制作的决策树时,代码崩溃了,因为我的数据存储在pandas DF(或np数组)中,而不是scikit-learn的bunch对象中。
现在,在Sci-kit learn - How to create a Bunch object 上,他们严厉警告我不要尝试创建bunch对象;但我也没有将我的DF或NP数组转换为上面的可视化函数所接受的内容的技能。
我们可以假设我的DF有九个特征和一个目标,称为“Feature01”,“Feature02”等和“Target01”。
这通常是我会这样拆分的。
FeatDF  = FullDF.drop( columns = ["Target01"])
LabelDF = FullDF["Target01"]

然后我愉快地开始分配分类器,或者如果是为了机器学习,则创建测试/训练拆分。但这些对于调用dtreeviz没有帮助 - 它需要像“feature_names”这样的内容(我认为这是“bunch”对象中包含的内容)。由于我无法将DF转换为bunch,所以我陷入了困境。请给我带来智慧。更新:我想任何简单的DF都可以说明我的难题。我们可以试一下。
import pandas as pd

Things = {'Feature01': [3,4,5,0], 
          'Feature02': [4,5,6,0], 
          'Feature03': [1,2,3,8], 
          'Target01': ['Red','Blue','Teal','Red']}
DF = pd.DataFrame(Things,
                  columns= ['Feature01', 'Feature02', 
                            'Feature02', 'Target01']) 

作为一个例子 DF。现在,我会去吗?
DataNP = DF.to_numpy()
classifier.fit(DF.data, DF.target)
feature_names = ['Feature01', 'Feature02', 'Feature03'] 
#..and what if I have 50 features...

viz = dtreeviz(classifier,
               DF.data,
               DF.target,
               target_name='Target01',
               feature_names=feature_names, 
               class_names=["Red", "Blue", "Teal"],
               fancy=False) 

或者这很愚蠢吗?到目前为止,感谢您的指导!

你能提供一个 [mcve] 以便我们可以复现这个问题吗? - SBylemans
你能提供一下你尝试调用dtreeviz的方式吗?因为我知道如何构建一个数据框,但我想知道如何使用数据框调用函数以及你遇到了什么错误。 - SBylemans
2个回答

10
  • sklearn's decision tree needs numerical target values
  • You can use sklearn's LabelEncoder to transform your strings to integers

    from sklearn import preprocessing
    
    label_encoder = preprocessing.LabelEncoder()
    label_encoder.fit(df.Target01)
    
    df['target'] = label_encoder.transform(df.Target01)
    
  • dtreeviz expects the class_names to be a list or dict, so let's get it from our label_encoder

    class_names = list(label_encoder.classes_)        
    

完整代码

import pandas as pd
from sklearn import preprocessing, tree
from dtreeviz.trees import dtreeviz

Things = {'Feature01': [3,4,5,0], 
          'Feature02': [4,5,6,0], 
          'Feature03': [1,2,3,8], 
          'Target01': ['Red','Blue','Teal','Red']}
df = pd.DataFrame(Things,
                  columns= ['Feature01', 'Feature02', 
                            'Feature02', 'Target01']) 

label_encoder = preprocessing.LabelEncoder()
label_encoder.fit(df.Target01)
df['target'] = label_encoder.transform(df.Target01)

classifier = tree.DecisionTreeClassifier()
classifier.fit(df.iloc[:,:3], df.target)

dtreeviz(classifier,
         df.iloc[:,:3],
         df.target,
         target_name='toy',
         feature_names=df.columns[0:3],
         class_names=list(label_encoder.classes_)
         )

enter image description here


旧回答

使用癌症数据集创建Pandas dataframe

df = pd.DataFrame(cancer.data, columns=cancer.feature_names)
df['target'] = cancer.target

这将给我们以下数据框。

mean radius mean texture    mean perimeter  mean area   mean smoothness mean compactness    mean concavity  mean concave points mean symmetry   mean fractal dimension  radius error    texture error   perimeter error area error  smoothness error    compactness error   concavity error concave points error    symmetry error  fractal dimension error worst radius    worst texture   worst perimeter worst area  worst smoothness    worst compactness   worst concavity worst concave points    worst symmetry  worst fractal dimension target
0   17.99   10.38   122.8   1001.0  0.1184  0.2776  0.3001  0.1471  0.2419  0.07871 1.095   0.9053  8.589   153.4   0.006399    0.04904 0.05373 0.01587 0.03003 0.006193    25.38   17.33   184.6   2019.0  0.1622  0.6656  0.7119  0.2654  0.4601  0.1189  0
1   20.57   17.77   132.9   1326.0  0.08474 0.07864 0.0869  0.07017 0.1812  0.05667 0.5435  0.7339  3.398   74.08   0.005225    0.01308 0.0186  0.0134  0.01389 0.003532    24.99   23.41   158.8   1956.0  0.1238  0.1866  0.2416  0.186   0.275   0.08902 0
2   19.69   21.25   130.0   1203.0  0.1096  0.1599  0.1974  0.1279  0.2069  0.05999 0.7456  0.7869  4.585   94.03   0.00615 0.04006 0.03832 0.02058 0.0225  0.004571    23.57   25.53   152.5   1709.0  0.1444  0.4245  0.4504  0.243   0.3613  0.08758 0
[...]
568 7.76    24.54   47.92   181.0   0.05263 0.04362 0.0 0.0 0.1587  0.05884 0.3857  1.428   2.548   19.15   0.007189    0.00466 0.0 0.0 0.02676 0.002783    9.456   30.37   59.16   268.6   0.08996 0.06444 0.0 0.0 0.2871  0.07039 1

您的分类器可以使用以下方式进行操作。
classifier.fit(df.iloc[:,:-1], df.target)

即将除最后一列外的所有列作为训练/输入,并将target列作为输出/目标。

可视化结果同理:

viz = dtreeviz(classifier,
               df.iloc[:,:-1],
               df.target,
               target_name='cancer',
               feature_names=df.columns[0:-1],
               class_names=["malignant", "benign"]) 

感谢您再次加入。在癌症数据集中,目标是整数,对吗?然而,当我使用玩具df和class_names = ["Red", "Blue", "Teal"]时,我得到了TypeError: can't multiply sequence by non-int of type 'float',并且当我说class_names = list(DF['Target01'].unique())时,它引发了一个不祥的KeyError: 3。这些有任何意义吗? - RandomForestRanger
抱歉,我应该在第二部分中补充说明,我还将红色更改为1,蓝色更改为2,青色更改为3... - RandomForestRanger
@RandomForestRanger:请检查更新后的答案,希望对您有用! - Maximilian Peters
哇。优雅。谢谢! - RandomForestRanger

1

我觉得你对文档中提供的示例感到困惑了。

在这里,让我们看一下使用鸢尾花数据集的示例。

from sklearn.datasets import *

# Loading iris data
iris = load_iris()

# Type of iris
type(iris)
<class 'sklearn.utils.Bunch'>

数据集被存储为sklearn Bunch对象,正如您所提到的。

但是dtreeviz在其任何参数中都不使用此对象。所有参数都是numpy数组。

# Iris data - parameter
type(iris.data)
<class 'numpy.ndarray'>

# Shape
data.data.shape
(150, 4)

所以很明显,dtreeviz方法是与numpy数组一起使用的,并且没有使用Bunch对象。在您的情况下,功能名称只是选定功能的列名称。
更新
# Replace the following the the sample code to fit your dataframe
cancer.data <> DF.iloc[:, :-1]
cancer.target <> DF['Target01']

# Other parameters
feature_names = DF.columns[:-1]
class_names = DF['Target01'].unique()

谢谢。你说得对,我确实有些困惑!假设我拿到了上面的DF - 我要将其转换为单个numpy数组并使用它吗?似乎不起作用。此外,在顶部的示例中,cancer.data和cancer.target不是colls - 所以似乎还有其他事情发生(除了feature_names = colls(我明白))。在最基本的层面上:您将如何处理玩具DF以使其适用于dtreeviz?再次感谢。 - RandomForestRanger
我已经更新了答案,告诉你如何集成你的样本数据框DF。它包括如果你有大量的特征和标签。如果你觉得有帮助,请在答案旁边选择复选框。干杯! - skillsmuggler
谢谢。我认为我们很接近了……也许我只是犯了一个显而易见的错误。上面的代码返回错误,说“Exception: class_names must be dict or sequence, not ndarray.”如果我将class_names = DF['Target01'].unique()替换为class_names = ["Red", "Blue", "Teal"],那么我会得到TypeError: can't multiply sequence by non-int of type 'float'的错误提示。 - RandomForestRanger
它期望一个类名的列表。您的错误消息指定您正在将列表与某个值相乘。确保您只将单个元素列表分配给class_names。尝试使用**list(DF['Target01'].unique())**。 - skillsmuggler
如果您发现解决方案有帮助,请给它点赞并选择复选框接受解决方案。 - skillsmuggler
仍未成功。class_names = list(DF['Target01'].unique() 返回相同的 TypeError。我无法让它工作。 - RandomForestRanger

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