决策树生成具有相同 类 的终端叶
Decision Tree generating terminal leaves with same classes
我对决策树比较陌生,而且我一直坚持使用我的决策树算法。我正在使用交叉验证和参数调整来优化 classification,遵循这个例子:https://medium.com/@haydar_ai/learning-data-science-day-22-cross-validation-and-parameter-tuning-b14bcbc6b012。但是无论我如何调整我的参数,我总是得到这样的结果(这里只是一个小树的例子):
Small Decision Tree Example
我不明白这种行为的原因。为什么树会生成具有相同 class 的叶子(此处为 class2)?为什么它不在 a<=0.375 = TRUE 之后简单地停止并用相同的 class 切割叶子(见图红色矩形)?有没有办法防止这种情况并使算法在此时停止?或者对这种行为有合理的解释吗?任何帮助或想法将不胜感激!谢谢!
编辑: 这是我的代码:
def load_csv(filename):
dataset = list()
with open(filename, 'r') as file:
csv_reader = reader(file)
for row in csv_reader:
if not row:
continue
dataset.append(row)
return dataset
# Convert string column to float
def str_column_to_float(dataset, column):
for row in dataset:
row[column] = float(row[column].strip())
# Load dataset
filename = 'C:/Test.csv'
dataset = load_csv(filename)
# convert string columns to float
for i in range(len(dataset[0])):
str_column_to_float(dataset, i)
# Transform to x and y
x = []
xpart = []
y = []
for row in dataset:
for i in range(len(row)):
if i != (len(row) - 1):
xpart.append(row[i])
else:
y.append(row[i])
x.append(xpart)
xpart = []
features_names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
labels = ['class1', 'class2']
#here I tried to tune the parameters
#(I changed them several times, this is just an example to show, how the code looks like).
# However, I always ended up with terminal leaves with same classes
"""dtree=DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=5,
max_features=8, max_leaf_nodes=None, min_impurity_decrease = 0.0, min_impurity_split = None, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
presort=False, random_state=None, splitter='random')"""
#here, I created the small example
dtree = DecisionTreeClassifier(max_depth=2)
dtree.fit(x,y)
dot_data = tree.export_graphviz(dtree, out_file=None)
graph = graphviz.Source(dot_data)
graph.render("Result")
dot_data = tree.export_graphviz(dtree, out_file=None,
feature_names= features_names,
class_names=labels,
filled=True, rounded=True,
special_characters=True)
graph = graphviz.Source(dot_data)
graph.format = 'png'
graph.render('Result', view = True)
...以及我的数据快照:
enter image description here
您所指的 class
属性是该特定节点的 多数 class,并且颜色来自 filled = True
您传递给 export_graphviz()
.
的参数
现在,查看您的数据集,您有 147 个 class1 样本和 525 个 class2 样本,这是一个相当不平衡的比率。碰巧的是,您的特定数据集在此深度的最佳拆分会产生大多数 class 为 class2 的拆分。这是正常行为,是您的数据的产物,鉴于 class2 比 class1 多出大约 3:1.
,这并不奇怪
至于为什么当分裂的两个 children 的大多数 class 相同时树不停止,这是因为算法的工作方式。如果没有最大深度而不受限制,它将继续,直到它只生成仅包含单个 class 的纯叶节点(并且 Gini impurity 为 0)。你在你的例子中设置了 max_depth = 2
,所以树在它可以产生所有纯节点之前就停止了。
您会注意到,在示例中用红色框起来的拆分中,右侧的节点几乎是 100% class2,有 54 个 class2 实例,并且class1 中只有 2 个。如果算法在此之前停止,它会产生上面的节点,291-45 class2-class1,这是没有用的。
也许您可以增加树的最大深度,看看是否可以进一步分离 classes。
我对决策树比较陌生,而且我一直坚持使用我的决策树算法。我正在使用交叉验证和参数调整来优化 classification,遵循这个例子:https://medium.com/@haydar_ai/learning-data-science-day-22-cross-validation-and-parameter-tuning-b14bcbc6b012。但是无论我如何调整我的参数,我总是得到这样的结果(这里只是一个小树的例子):
Small Decision Tree Example
我不明白这种行为的原因。为什么树会生成具有相同 class 的叶子(此处为 class2)?为什么它不在 a<=0.375 = TRUE 之后简单地停止并用相同的 class 切割叶子(见图红色矩形)?有没有办法防止这种情况并使算法在此时停止?或者对这种行为有合理的解释吗?任何帮助或想法将不胜感激!谢谢!
编辑: 这是我的代码:
def load_csv(filename):
dataset = list()
with open(filename, 'r') as file:
csv_reader = reader(file)
for row in csv_reader:
if not row:
continue
dataset.append(row)
return dataset
# Convert string column to float
def str_column_to_float(dataset, column):
for row in dataset:
row[column] = float(row[column].strip())
# Load dataset
filename = 'C:/Test.csv'
dataset = load_csv(filename)
# convert string columns to float
for i in range(len(dataset[0])):
str_column_to_float(dataset, i)
# Transform to x and y
x = []
xpart = []
y = []
for row in dataset:
for i in range(len(row)):
if i != (len(row) - 1):
xpart.append(row[i])
else:
y.append(row[i])
x.append(xpart)
xpart = []
features_names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
labels = ['class1', 'class2']
#here I tried to tune the parameters
#(I changed them several times, this is just an example to show, how the code looks like).
# However, I always ended up with terminal leaves with same classes
"""dtree=DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=5,
max_features=8, max_leaf_nodes=None, min_impurity_decrease = 0.0, min_impurity_split = None, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
presort=False, random_state=None, splitter='random')"""
#here, I created the small example
dtree = DecisionTreeClassifier(max_depth=2)
dtree.fit(x,y)
dot_data = tree.export_graphviz(dtree, out_file=None)
graph = graphviz.Source(dot_data)
graph.render("Result")
dot_data = tree.export_graphviz(dtree, out_file=None,
feature_names= features_names,
class_names=labels,
filled=True, rounded=True,
special_characters=True)
graph = graphviz.Source(dot_data)
graph.format = 'png'
graph.render('Result', view = True)
...以及我的数据快照:
enter image description here
您所指的 class
属性是该特定节点的 多数 class,并且颜色来自 filled = True
您传递给 export_graphviz()
.
现在,查看您的数据集,您有 147 个 class1 样本和 525 个 class2 样本,这是一个相当不平衡的比率。碰巧的是,您的特定数据集在此深度的最佳拆分会产生大多数 class 为 class2 的拆分。这是正常行为,是您的数据的产物,鉴于 class2 比 class1 多出大约 3:1.
,这并不奇怪至于为什么当分裂的两个 children 的大多数 class 相同时树不停止,这是因为算法的工作方式。如果没有最大深度而不受限制,它将继续,直到它只生成仅包含单个 class 的纯叶节点(并且 Gini impurity 为 0)。你在你的例子中设置了 max_depth = 2
,所以树在它可以产生所有纯节点之前就停止了。
您会注意到,在示例中用红色框起来的拆分中,右侧的节点几乎是 100% class2,有 54 个 class2 实例,并且class1 中只有 2 个。如果算法在此之前停止,它会产生上面的节点,291-45 class2-class1,这是没有用的。
也许您可以增加树的最大深度,看看是否可以进一步分离 classes。