{"action":"created","issue":{"url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/5080","labels_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/5080/labels{/name}","comments_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/5080/comments","events_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/5080/events","html_url":"https://github.com/scikit-learn/scikit-learn/issues/5080","id":98662005,"number":5080,"title":"Polymorphic clone","user":{"login":"jnothman","id":78827,"avatar_url":"https://avatars.githubusercontent.com/u/78827?v=3","gravatar_id":"","url":"https://api.github.com/users/jnothman","html_url":"https://github.com/jnothman","followers_url":"https://api.github.com/users/jnothman/followers","following_url":"https://api.github.com/users/jnothman/following{/other_user}","gists_url":"https://api.github.com/users/jnothman/gists{/gist_id}","starred_url":"https://api.github.com/users/jnothman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jnothman/subscriptions","organizations_url":"https://api.github.com/users/jnothman/orgs","repos_url":"https://api.github.com/users/jnothman/repos","events_url":"https://api.github.com/users/jnothman/events{/privacy}","received_events_url":"https://api.github.com/users/jnothman/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/scikit-learn/scikit-learn/labels/API","name":"API","color":"bfd4f2"},{"url":"https://api.github.com/repos/scikit-learn/scikit-learn/labels/Enhancement","name":"Enhancement","color":"d7e102"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":15,"created_at":"2015-08-03T03:02:35Z","updated_at":"2015-08-15T13:29:52Z","closed_at":null,"body":"`sklearn.base.clone` is defined to reconstruct an object of the argument's type with its constructor parameters (from `get_params(deep=False)`) recursively cloned.\r\n\r\nThere are cases where I think the One Obvious Way to provide an API entails allowing polymorphic overriding of clone behaviour. In particular, my [longstanding implementation](https://github.com/jnothman/scikit-learn/tree/remember) of wrappers for memoized and frozen estimators relies on this, and I would like to have that library of utilities not depend on a change to `sklearn.base`. So we need to patch the latter.\r\n\r\nLet me try to explain. Let's say we want a way to freeze a model. That is, cloning it should not flush its fit attributes, and calling `fit` again should not affect it. A syntax like the following seems far and away the clearest:\r\n```python\r\nest = freeze_model(MyEstimator().fit(special_X, special_Y))\r\n```\r\n\r\nIt should be obvious that the standard definition of `clone` won't make this operate very easily: we need to keep more than will be returned by `get_params`, unless `MyEstimator().__dict__` becomes a param of the `freeze_model` instance, which is pretty hacky.\r\n\r\nAlternative syntax could be class decoration (`freeze_model(MyEstimator)()`) or mixin (`class MyFrozenEstimator(MyEstimator, FrozenModel): pass`) such that the first call to `fit` then sets a frozen model. These are not only uglier, but encounter the same problems.\r\n\r\nIdeally this sort of estimator wrapper should pass through `{set,get}_params` of the wrapped estimator without adding underscored prefixes (not that this is so pertinent for a frozen model, but for other applications of similar wrappers). It should also delegate all attributes to the wrapped estimator. Without making a mess of `freeze_model.__init__` this is also not possible, IMO, without redefining `clone`.\r\n\r\nSo. Can we agree:\r\n* that it would not be a Bad Thing to allow polymporphism in cloning?\r\n* on a name for the polymorphic clone method: `clone` or `clone_params` or `sklearn_clone`\r\n?"},"comment":{"url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/comments/131374725","html_url":"https://github.com/scikit-learn/scikit-learn/issues/5080#issuecomment-131374725","issue_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/5080","id":131374725,"user":{"login":"jnothman","id":78827,"avatar_url":"https://avatars.githubusercontent.com/u/78827?v=3","gravatar_id":"","url":"https://api.github.com/users/jnothman","html_url":"https://github.com/jnothman","followers_url":"https://api.github.com/users/jnothman/followers","following_url":"https://api.github.com/users/jnothman/following{/other_user}","gists_url":"https://api.github.com/users/jnothman/gists{/gist_id}","starred_url":"https://api.github.com/users/jnothman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jnothman/subscriptions","organizations_url":"https://api.github.com/users/jnothman/orgs","repos_url":"https://api.github.com/users/jnothman/repos","events_url":"https://api.github.com/users/jnothman/events{/privacy}","received_events_url":"https://api.github.com/users/jnothman/received_events","type":"User","site_admin":false},"created_at":"2015-08-15T13:29:52Z","updated_at":"2015-08-15T13:29:52Z","body":"(Some minor thoughts on this: if a mixin is deemeed appropriate, a syntax like `memoized_estimator(SomeEstimator())` could be achieved by dynamically defining the mixed-in class. While magic already, making this pickleable would require `__reduce__` magic, too.)"}}