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

[ENH] Learner widgets: Inform about potential problems when overriding preprocessors #5710

Merged
merged 5 commits into from
Jan 7, 2022

Conversation

janezd
Copy link
Contributor

@janezd janezd commented Nov 26, 2021

Issue

Resolves #5703. Fixes #5577.

Description of changes
  • Inform when preprocessors are given and the learner has its own default preprocessors, which are thusly overriden.
  • Fix invalidation of model and learner, calling of updates and outputting signals.

Missing coverage is mostly in stack learner and was already missed before. This PR won't add tests there.

Includes
  • Code changes
  • Tests

@codecov
Copy link

codecov bot commented Nov 26, 2021

Codecov Report

Merging #5710 (e44754d) into master (3408e32) will increase coverage by 0.04%.
The diff coverage is 90.47%.

@@            Coverage Diff             @@
##           master    #5710      +/-   ##
==========================================
+ Coverage   86.11%   86.16%   +0.04%     
==========================================
  Files         315      315              
  Lines       66093    66214     +121     
==========================================
+ Hits        56918    57050     +132     
+ Misses       9175     9164      -11     

@markotoplak markotoplak changed the title Learner widgets: Inform about potential problems when overriding preprocessors [ENH] Learner widgets: Inform about potential problems when overriding preprocessors Nov 26, 2021
@markotoplak
Copy link
Member

I think the message is not correct for current Orange's behavior. I like what the message implies, so perhaps we should change what Orange does.

Look, from the edited file:

    def update_learner(self):
        self.learner = self.create_learner()
        if self.learner and issubclass(self.LEARNER, Fitter):
            self.learner.use_default_preprocessors = True

create_learner() passes the given preprocessors into the learner, but in Learner we have:

    @property
    def active_preprocessors(self):
        yield from self.preprocessors
        if (self.use_default_preprocessors and
                self.preprocessors is not type(self).preprocessors):
            yield from type(self).preprocessors

If I understand this code, the default preprocessors will still be used for Fitters, the explicitly input ones are only meant to be used before the fixed ones.

Logistic regression in Orange is not a Fitter so in this specific case the message is correct, but is wrong for Fitters.

Why are Fitters (learners that can do both classification or regression) handled differently? No idea.

@markotoplak
Copy link
Member

Perhaps we can make a different message for Fitters for now and then think about changing the behavior separately?

I have no idea what would that kind of a behavior change mean for backward compatibility, but it could get nasty. :D

@janezd janezd force-pushed the baselearnerwidget-pp-warning branch from 5137da5 to a0fc168 Compare December 3, 2021 14:44
@janezd janezd force-pushed the baselearnerwidget-pp-warning branch from a0fc168 to 6176b2c Compare December 3, 2021 15:03

def handleNewSignals(self):
super().handleNewSignals()
self.apply()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have called unconditional_apply. Now the base class defines handleNewSignals and handles them properly (I suppose).

@@ -226,8 +245,7 @@ def settings_changed(self, *args, **kwargs):
def _change_name(self, instance, output):
if instance:
instance.name = self.effective_learner_name()
if self.auto_apply:
output.send(instance)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was incorrect because it didn't set dirty flag, but was necessary due to broken signal handling.

@janezd janezd force-pushed the baselearnerwidget-pp-warning branch from 6176b2c to b4f0b96 Compare December 3, 2021 15:23
@janezd janezd force-pushed the baselearnerwidget-pp-warning branch from b4f0b96 to 8c42dbe Compare December 3, 2021 16:11
self.model or self.update_model()

def apply_as(self, level, unconditional=False):
self.__apply_level.append(level)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is horrendous, but I see no way around it (while maintaining compatibility).

This class and derived classes used apply to update and send both models; it would be better to update just the invalidated. Furthermore _change_name sent outputs by itself if auto_apply was True, but of course could not set the dirty flag if it was False. In some cases, this caused outputing the model twice...

To clean the mess, yet keep the compatilbility, I had a solution in which apply got an additional argument with default value. Unfortunatelly, gui.auto_apply doesn't pass extra arguments to apply -- and we shouldn't modify it to, just to fix this specific case.

To make it even more tricky, the function as defined here is called only when auto apply is on.

Hence, apply_as passes an argument by appending the "urgency" to the list. When the apply function is actually called, it finds the maximal "urgency" in the list and acts on it.

self.assertFalse(wyes.Information.ignored_preprocessors.is_shown())
self.assertFalse(wfit.Information.ignored_preprocessors.is_shown())

def test_multiple_sends(self):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test would fail on master because learner would be sent twice.

@lanzagar lanzagar merged commit 41f6906 into biolab:master Jan 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants