Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Tree widget binarization #1837

Merged
merged 2 commits into from
Jan 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Orange/widgets/classify/owclassificationtree.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

from Orange.data import Table
from Orange.modelling.tree import TreeLearner
from Orange.classification.tree import TreeLearner as ClassificationTreeLearner
from Orange.widgets.model.owtree import OWTreeLearner
from Orange.widgets.utils.owlearnerwidget import OWBaseLearner
from Orange.widgets.widget import Msg


class OWTreeLearner(OWTreeLearner):
Expand All @@ -21,6 +23,29 @@ class OWTreeLearner(OWTreeLearner):
"limit_majority", "sufficient_majority", 51, 100),) + \
OWTreeLearner.spin_boxes[-1:]

class Error(OWTreeLearner.Error):
cannot_binarize = Msg("Binarization cannot handle '{}'\n"
"because it has {} values. "
"Binarization can handle up to {}.\n"
"Disable 'Induce binary tree' to proceed.")

def check_data(self):
self.Error.cannot_binarize.clear()
if not super().check_data():
return False
if not self.binary_trees:
return True
max_values, max_attr = max(
((len(attr.values), attr)
for attr in self.data.domain.attributes if attr.is_discrete),
default=(0, None))
MAX_BINARIZATION = ClassificationTreeLearner.MAX_BINARIZATION
if max_values > MAX_BINARIZATION:
self.Error.cannot_binarize(
max_attr.name, max_values, MAX_BINARIZATION)
return False
return True

def learner_kwargs(self):
opts = super().learner_kwargs()
opts['sufficient_majority'] = \
Expand Down
54 changes: 54 additions & 0 deletions Orange/widgets/classify/tests/test_owclassificationtree.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# Test methods with long descriptive names can omit docstrings
# pylint: disable=missing-docstring
from Orange.data import Table, Domain, DiscreteVariable
from Orange.classification.tree import TreeLearner as ClassificationTreeLearner
from Orange.base import Model
from Orange.widgets.classify.owclassificationtree import OWTreeLearner
from Orange.widgets.tests.base import (WidgetTest, DefaultParameterMapping,
ParameterMapping, WidgetLearnerTestMixin)


class TestOWClassificationTree(WidgetTest, WidgetLearnerTestMixin):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.iris = Table("iris")

def setUp(self):
self.widget = self.create_widget(
OWTreeLearner, stored_settings={"auto_apply": False})
Expand Down Expand Up @@ -34,3 +41,50 @@ def test_parameters_unchecked(self):
for par, val in zip(self.parameters, (None, 2, 1))]
self.test_parameters()

def test_cannot_binarize(self):
widget = self.widget
error_shown = widget.Error.cannot_binarize.is_shown
self.assertFalse(error_shown())
self.send_signal("Data", self.iris)

# The widget outputs ClassificationTreeLearner.
# If not, below tests may not make sense
learner = self.get_output("Learner")
dlearner = learner.get_learner(learner.CLASSIFICATION)
self.assertTrue(dlearner, ClassificationTreeLearner)

# No error on Iris
max_binarization = dlearner.MAX_BINARIZATION
self.assertFalse(error_shown())

# Error when too many values
domain = Domain([
DiscreteVariable(
values=[str(x) for x in range(max_binarization + 1)])],
DiscreteVariable(values="01"))
self.send_signal("Data", Table(domain, [[0, 0], [1, 1]]))
self.assertTrue(error_shown())
# No more error on Iris
self.send_signal("Data", self.iris)
self.assertFalse(error_shown())

# Checking and unchecking binarization works
widget.controls.binary_trees.click()
self.assertFalse(widget.binary_trees)
widget.unconditional_apply()
self.send_signal("Data", Table(domain, [[0, 0], [1, 1]]))
self.assertFalse(error_shown())
widget.controls.binary_trees.click()
widget.unconditional_apply()
self.assertTrue(error_shown())
widget.controls.binary_trees.click()
widget.unconditional_apply()
self.assertFalse(error_shown())

# If something is wrong with the data, no error appears
domain = Domain([
DiscreteVariable(
values=[str(x) for x in range(max_binarization + 1)])],
DiscreteVariable(values="01"))
self.send_signal("Data", Table(domain))
self.assertFalse(error_shown())
5 changes: 3 additions & 2 deletions Orange/widgets/utils/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ def update_message_state(self):
elif self.message_bar is not None:
font_size = self.message_bar.fontInfo().pixelSize()
group = messages[0].group
text = str(messages[0]) if len(messages) == 1 \
text = str(messages[0]).split("\n")[0] if len(messages) == 1 \
else "{} problems during execution".format(len(messages))
# TODO: fix tooltip background color - it is not white
tooltip = ''.join(
Expand All @@ -346,7 +346,8 @@ def update_message_state(self):
&nbsp;&nbsp;&nbsp;</nobr>
<span style="font-size:9pt"><br></span>
</p>'''.
format(msg.group.bar_background, font_size, str(msg))
format(msg.group.bar_background, font_size,
str(msg).replace("\n", "<br/>&nbsp;&nbsp;&nbsp; "))
for msg in messages)
self._set_message_bar(group, text, tooltip)

Expand Down