Skip to content

[WIP] Implemented SelectFromModel meta-transformer #3011

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

Closed
wants to merge 17 commits into from

Conversation

maheshakya
Copy link
Contributor

Fix for #2160
Implemented a meta-transformer to with _LearntSelectorMixin. Test cases are included.
Documentation(with examples) needs to be completed.

@jnothman
Copy link
Member

Thanks for tackling this. A number of points:

  • please put this in the same file as _LearntSelectorMixin
  • although I suggested inheriting from _LearntSelectorMixin, it isn't sufficient for correct operation. _LearntSelectorMixin.transform inspects the estimator directly, e.g. to inspect the penalty parameter. You will need to turn _LearntSelectorMixin.transform into one or more functions.
  • You shouldn't set any underscore-suffixed attributes in your estimator's __init__. This should be done in fit. It's fine to postpone validation to fit.
  • You shouldn't need to have estimator_params. clone will keep any settings, and BaseEstimator will handle the delegation of attribute setting so that this can work in grid search.
  • SelectFromModel should accept two parameters: estimator and threshold.
  • I am not sure about duplicating the coefficients here to store them as an attribute. It would be more relevant to store the aggregate feature importances: because _LearntSelectorMixin currently has to sum over the coefficients for multiclass linear models, it might be useful to see the summed features.) But it's not essential to store these locally.
  • It would also be nice to have an attribute threshold_ since _LearntSelectorMixin's calculation of the actual threshold can be non-trivial.
  • SelectFromModel should inherit from sklearn.feature_selection.base.SelectorMixin and implement _get_support_mask.
  • This PR should include the deprecation of _LearntSelectorMixin. Use the @deprecated decorator on transform.

I'm changing this PR to a [WIP]. I hope that's alright with you.

@jnothman
Copy link
Member

Also, the failing tests happen because this can't be constructed as it is. I think it should be included here: https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/utils/testing.py#L441.

And although it does nothing at the moment, please inherit from sklearn.base.MetaEstimatorMixin.

@jnothman jnothman changed the title [MRG] Implemented SelectFromModel meta-transformer [WIP] Implemented SelectFromModel meta-transformer Mar 27, 2014
@maheshakya
Copy link
Contributor Author

I have separated out the section where threshold, importances and penalty is retrieved in _LearntSelectorMixin into two functions. One of them uses @depricated decorator.

Other issues are fixed.


return estimator

def __init__(self, estimator=None, threshold=None):
Copy link
Member

Choose a reason for hiding this comment

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

Please move this method to right below the class docstring.

estimator=None is not useful. Leave it without a default.

@maheshakya
Copy link
Contributor Author

Since threshold in now a parameter to SelectFromModel, transform function should use that value. So in that case the value taken from the transform function will be useless.
Is this a correct way?

When transform function is called from another estimator, it will act in the usual way.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 9506120 on maheshakya:select_from_model into eb10c4c on scikit-learn:master.

@jnothman
Copy link
Member

So in that case the value taken from the transform function will be useless.

The correct way is to redefine transform in the metaestimator not to take a threshold parameter.

if self.estimator_ is None:
raise ValueError("estimator cannot be None")

def _make_estimator(self):
Copy link
Member

Choose a reason for hiding this comment

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

Please inline this method.

@jnothman
Copy link
Member

I don't think it's a good idea to store support_mask_. It is inconsistent with other feature selectors, duplicates the get_support method provided by SelectorMixin, and means you can't change the threshold and just call get_support to reevaluate it.

self.estimator = self._make_estimator()

# Convert data
X, y = check_arrays(X, y)
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this belongs here. It's the base estimator's business.

@jnothman
Copy link
Member

Btw, it may be cleaner to implement this with the metaestimator not inheriting from the mixin. Please feel free to do it that way if you think it improves the code.

@maheshakya
Copy link
Contributor Author

I couldn't find a way to implement _get_support_mask function without storing the mask in the transform function without duplicating the code. So I made it a private member.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling be4f070 on maheshakya:select_from_model into fbe974b on scikit-learn:master.

@jnothman
Copy link
Member

This should probably support partial_fit. It should possibly also support warm_start, which would involve not using clone.

@maheshakya
Copy link
Contributor Author

@jnothman, I apologize for the inconvenience, Can you explain what exactly needs to be done in partial_fit. I checked out several estimators that defines it. But those seem to be performing different tasks.

importances = estimator.feature_importances_
if importances is None:
raise ValueError("Importance weights not computed. Please set "
"the compute_importances parameter before fit.")
Copy link
Contributor

Choose a reason for hiding this comment

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

This is deprecated in forests. You can remove this if-statement.

@jnothman
Copy link
Member

partial_fit allows a model to be trained without keeping all the training data in memory (or providing it) at once. Here, partial_fit should create estimator_ only on the first call, and call estimator_.partial_fit for each call.

The only reason I say it's necessary is because it's a way the current mixin can be used.

@maheshakya
Copy link
Contributor Author

I have added partial_fit and warm_start.

BTW is there something wrong with Travis CI? It doesn't seem to be building my last two commits.

@jnothman
Copy link
Member

jnothman commented Apr 1, 2014

BTW is there something wrong with Travis CI? It doesn't seem to be building my last two commits.

It's highly non user-friendly, but this means that it can't automatically merge your work with master, which it does before testing. Could you please rebase on the current master and force-push the rebased branch?

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 9a41f2f on maheshakya:select_from_model into fec2867 on scikit-learn:master.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 1469c48 on maheshakya:select_from_model into fec2867 on scikit-learn:master.

Returns self.
"""
if not hasattr(self.estimator, "partial_fit"):
raise(AttributeError, "estimator does not have"
Copy link
Member

Choose a reason for hiding this comment

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

That ( can't be there for this to be correct syntax in Python 3.

But I think it's fine if you don't explicitly check this case. The AttributeError produced by self.estimator_.partial_fit (e.g. ''LinearSVC' object has no attribute 'partial_fit'') is clear enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I agree.
I removed the test case for that as well.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling ccbab10 on maheshakya:select_from_model into fec2867 on scikit-learn:master.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 77b30e4 on maheshakya:select_from_model into fec2867 on scikit-learn:master.

@jnothman
Copy link
Member

jnothman commented Apr 1, 2014

I'm not sure the tests are quite satisfactory yet (and I might not be around for the next few days to take another look), but I think we need to seek opinions as to whether a meta-estimator improves on the mixin. @glouppe, WDYT, and who else is likely to be opinionated on this?

@maheshakya
Copy link
Contributor Author

What are the tests that need to be improved. I can work on those.

@jnothman
Copy link
Member

jnothman commented Apr 2, 2014

I'm not able to look in great detail at the tests right now, but in order
for this patch to be complete, internal uses of the old (mixin) behaviour
need to be changed, including in documentation and examples, including
https://github.com/scikit-learn/scikit-learn/blob/master/doc/modules/feature_selection.rst#l1-based-feature-selection,
https://github.com/scikit-learn/scikit-learn/blob/master/doc/modules/feature_selection.rst#tree-based-feature-selectionand
probably other places.

On 2 April 2014 02:35, maheshakya notifications@github.com wrote:

What are the tests that need to be improved. I can work on those.

Reply to this email directly or view it on GitHubhttps://github.com//pull/3011#issuecomment-39220058
.

@maheshakya
Copy link
Contributor Author

Thanks. I will give it a shot. (for improved test cases, examples and documentation)

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 7f12af3 on maheshakya:select_from_model into fec2867 on scikit-learn:master.

@coveralls
Copy link

Coverage Status

Coverage remained the same when pulling 11d1e81 on maheshakya:select_from_model into fec2867 on scikit-learn:master.

@maheshakya
Copy link
Contributor Author

I suppose we need to change every example that uses feature selection based on LearntSelectorMixin, right?

@jnothman
Copy link
Member

Yes, unfortunately.

@MechCoder
Copy link
Member

It seems that there are unrelated changes. I'm not sure how adding a meta-transformer should affect travis.yml

@MechCoder
Copy link
Member

Closed in favor of #4242 . I rescued this PR from git hell!

@MechCoder MechCoder closed this Feb 12, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants