We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
step: removing 5 features in each iteration
Using RFECV, the graph shows best features with one increment in each iteration.
I want to show each iteration should work with an increment of 5 features.
Example: score  should be plotted against x-axis of [5,10,15,20,25].
I used step=5, but its not working.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `yellowbrick/features/rfecv.py`
Content:
```
1 # yellowbrick.features.rfecv
2 # Visualize the number of features selected with recursive feature elimination
3 #
4 # Author:  Benjamin Bengfort <benjamin@bengfort.com>
5 # Created: Tue Apr 03 17:31:37 2018 -0400
6 #
7 # ID: rfecv.py [] benjamin@bengfort.com $
8 
9 """
10 Visualize the number of features selected using recursive feature elimination
11 """
12 
13 ##########################################################################
14 ## Imports
15 ##########################################################################
16 
17 import numpy as np
18 
19 from yellowbrick.base import ModelVisualizer
20 from yellowbrick.exceptions import YellowbrickValueError
21 
22 from sklearn.utils import check_X_y
23 from sklearn.feature_selection import RFE
24 from sklearn.model_selection import cross_val_score
25 
26 
27 ##########################################################################
28 ## Recursive Feature Elimination
29 ##########################################################################
30 
31 class RFECV(ModelVisualizer):
32     """
33     Recursive Feature Elimination, Cross-Validated (RFECV) feature selection.
34 
35     Selects the best subset of features for the supplied estimator by removing
36     0 to N features (where N is the number of features) using recursive
37     feature elimination, then selecting the best subset based on the
38     cross-validation score of the model. Recursive feature elimination
39     eliminates n features from a model by fitting the model multiple times and
40     at each step, removing the weakest features, determined by either the
41     ``coef_`` or ``feature_importances_`` attribute of the fitted model.
42 
43     The visualization plots the score relative to each subset and shows trends
44     in feature elimination. If the feature elimination CV score is flat, then
45     potentially there are not enough features in the model. An ideal curve is
46     when the score jumps from low to high as the number of features removed
47     increases, then slowly decreases again from the optimal number of
48     features.
49 
50     Parameters
51     ----------
52     model : a scikit-learn estimator
53         An object that implements ``fit`` and provides information about the
54         relative importance of features with either a ``coef_`` or
55         ``feature_importances_`` attribute.
56 
57         Note that the object is cloned for each validation.
58 
59     ax : matplotlib.Axes object, optional
60         The axes object to plot the figure on.
61 
62     step : int or float, optional (default=1)
63         If greater than or equal to 1, then step corresponds to the (integer)
64         number of features to remove at each iteration. If within (0.0, 1.0),
65         then step corresponds to the percentage (rounded down) of features to
66         remove at each iteration.
67 
68     groups : array-like, with shape (n_samples,), optional
69         Group labels for the samples used while splitting the dataset into
70         train/test set.
71 
72     cv : int, cross-validation generator or an iterable, optional
73         Determines the cross-validation splitting strategy.
74         Possible inputs for cv are:
75 
76           - None, to use the default 3-fold cross-validation,
77           - integer, to specify the number of folds.
78           - An object to be used as a cross-validation generator.
79           - An iterable yielding train/test splits.
80 
81         see the scikit-learn
82         `cross-validation guide <http://scikit-learn.org/stable/modules/cross_validation.html>`_
83         for more information on the possible strategies that can be used here.
84 
85     scoring : string, callable or None, optional, default: None
86         A string or scorer callable object / function with signature
87         ``scorer(estimator, X, y)``. See scikit-learn model evaluation
88         documentation for names of possible metrics.
89 
90     kwargs : dict
91         Keyword arguments that are passed to the base class and may influence
92         the visualization as defined in other Visualizers.
93 
94     Attributes
95     ----------
96     n_features_ : int
97         The number of features in the selected subset
98 
99     support_ : array of shape [n_features]
100         A mask of the selected features
101 
102     ranking_ : array of shape [n_features]
103         The feature ranking, such that ``ranking_[i]`` corresponds to the
104         ranked position of feature i. Selected features are assigned rank 1.
105 
106     cv_scores_ : array of shape [n_subsets_of_features, n_splits]
107         The cross-validation scores for each subset of features and splits in
108         the cross-validation strategy.
109 
110     rfe_estimator_ : sklearn.feature_selection.RFE
111         A fitted RFE estimator wrapping the original estimator. All estimator
112         functions such as ``predict()`` and ``score()`` are passed through to
113         this estimator (it rewraps the original model).
114 
115     Notes
116     -----
117     This model wraps ``sklearn.feature_selection.RFE`` and not
118     ``sklearn.feature_selection.RFECV`` because access to the internals of the
119     CV and RFE estimators is required for the visualization. The visualizer
120     does take similar arguments, however it does not expose the same internal
121     attributes.
122 
123     Additionally, the RFE model can be accessed via the ``rfe_estimator_``
124     attribute. Once fitted, the visualizer acts as a wrapper for this
125     estimator and not for the original model passed to the model. This way the
126     visualizer model can be used to make predictions.
127 
128     .. caution:: This visualizer requires a model that has either a ``coef_``
129         or ``feature_importances_`` attribute when fitted.
130     """
131 
132     def __init__(self, model, ax=None, step=1, groups=None, cv=None,
133                  scoring=None, **kwargs):
134 
135         # Initialize the model visualizer
136         super(RFECV, self).__init__(model, ax=ax, **kwargs)
137 
138         # Set parameters
139         self.set_params(step=step, groups=groups, cv=cv, scoring=scoring)
140 
141     def fit(self, X, y=None):
142         """
143         Fits the RFECV with the wrapped model to the specified data and draws
144         the rfecv curve with the optimal number of features found.
145 
146         Parameters
147         ----------
148         X : array-like, shape (n_samples, n_features)
149             Training vector, where n_samples is the number of samples and
150             n_features is the number of features.
151 
152         y : array-like, shape (n_samples) or (n_samples, n_features), optional
153             Target relative to X for classification or regression.
154 
155         Returns
156         -------
157         self : instance
158             Returns the instance of the RFECV visualizer.
159         """
160         X, y = check_X_y(X, y, "csr")
161         n_features = X.shape[1]
162 
163         # This check is kind of unnecessary since RFE will do it, but it's
164         # nice to get it out of the way ASAP and raise a meaningful error.
165         if 0.0 < self.step < 1.0:
166             step = int(max(1, self.step * n_features))
167         else:
168             step = int(self.step)
169 
170         if step < 0:
171             raise YellowbrickValueError("step must be >0")
172 
173         # Create the RFE model
174         rfe = RFE(self.estimator, step=step)
175         n_feature_subsets = np.arange(1, n_features+1)
176 
177         # Create the cross validation params
178         # TODO: handle random state
179         cv_params = {
180             key: self.get_params()[key]
181             for key in ('groups', 'cv', 'scoring')
182         }
183 
184         # Perform cross-validation for each feature subset
185         scores = []
186         for n_features_to_select in n_feature_subsets:
187             rfe.set_params(n_features_to_select=n_features_to_select)
188             scores.append(cross_val_score(rfe, X, y, **cv_params))
189 
190         # Convert scores to array
191         self.cv_scores_ = np.array(scores)
192 
193         # Find the best RFE model
194         bestidx = self.cv_scores_.mean(axis=1).argmax()
195         self.n_features_ = n_feature_subsets[bestidx]
196 
197         # Fit the final RFE model for the number of features
198         self.rfe_estimator_ = rfe
199         self.rfe_estimator_.set_params(n_features_to_select=self.n_features_)
200         self.rfe_estimator_.fit(X, y)
201 
202         # Rewrap the visualizer to use the rfe estimator
203         self._wrapped = self.rfe_estimator_
204 
205         # Hoist the RFE params to the visualizer
206         self.support_ = self.rfe_estimator_.support_
207         self.ranking_ = self.rfe_estimator_.ranking_
208 
209         self.draw()
210         return self
211 
212     def draw(self, **kwargs):
213         """
214         Renders the rfecv curve.
215         """
216         # Compute the curves
217         x = np.arange(1, len(self.cv_scores_)+1)
218         means = self.cv_scores_.mean(axis=1)
219         sigmas = self.cv_scores_.std(axis=1)
220 
221 
222         # Plot one standard deviation above and below the mean
223         self.ax.fill_between(x, means - sigmas, means+sigmas, alpha=0.25)
224 
225         # Plot the curve
226         self.ax.plot(x, means, 'o-')
227 
228         # Plot the maximum number of features
229         self.ax.axvline(
230             self.n_features_, c='k', ls='--',
231             label="n_features = {}\nscore = {:0.3f}".format(
232                 self.n_features_, self.cv_scores_.mean(axis=1).max()
233             )
234         )
235 
236         return self.ax
237 
238     def finalize(self, **kwargs):
239         """
240         Add the title, legend, and other visual final touches to the plot.
241         """
242         # Set the title of the figure
243         self.set_title('RFECV for {}'.format(self.name))
244 
245         # Add the legend
246         self.ax.legend(frameon=True, loc='best')
247 
248         # Set the axis labels
249         self.ax.set_xlabel('Number of Features Selected')
250         self.ax.set_ylabel('Score')
251 
252 
253 ##########################################################################
254 ## Quick Methods
255 ##########################################################################
256 
257 def rfecv(model, X, y, ax=None, step=1, groups=None, cv=None,
258           scoring=None, **kwargs):
259     """
260     Performs recursive feature elimination with cross-validation to determine
261     an optimal number of features for a model. Visualizes the feature subsets
262     with respect to the cross-validation score.
263 
264     This helper function is a quick wrapper to utilize the RFECV visualizer
265     for one-off analysis.
266 
267     Parameters
268     ----------
269     model : a scikit-learn estimator
270         An object that implements ``fit`` and provides information about the
271         relative importance of features with either a ``coef_`` or
272         ``feature_importances_`` attribute.
273 
274         Note that the object is cloned for each validation.
275 
276     X : array-like, shape (n_samples, n_features)
277         Training vector, where n_samples is the number of samples and
278         n_features is the number of features.
279 
280     y : array-like, shape (n_samples) or (n_samples, n_features), optional
281         Target relative to X for classification or regression.
282 
283     ax : matplotlib.Axes object, optional
284         The axes object to plot the figure on.
285 
286     step : int or float, optional (default=1)
287         If greater than or equal to 1, then step corresponds to the (integer)
288         number of features to remove at each iteration. If within (0.0, 1.0),
289         then step corresponds to the percentage (rounded down) of features to
290         remove at each iteration.
291 
292     groups : array-like, with shape (n_samples,), optional
293         Group labels for the samples used while splitting the dataset into
294         train/test set.
295 
296     cv : int, cross-validation generator or an iterable, optional
297         Determines the cross-validation splitting strategy.
298         Possible inputs for cv are:
299 
300           - None, to use the default 3-fold cross-validation,
301           - integer, to specify the number of folds.
302           - An object to be used as a cross-validation generator.
303           - An iterable yielding train/test splits.
304 
305         see the scikit-learn
306         `cross-validation guide <http://scikit-learn.org/stable/modules/cross_validation.html>`_
307         for more information on the possible strategies that can be used here.
308 
309     scoring : string, callable or None, optional, default: None
310         A string or scorer callable object / function with signature
311         ``scorer(estimator, X, y)``. See scikit-learn model evaluation
312         documentation for names of possible metrics.
313 
314     kwargs : dict
315         Keyword arguments that are passed to the base class and may influence
316         the visualization as defined in other Visualizers. These arguments are
317         also passed to the `poof()` method, e.g. can pass a path to save the
318         figure to.
319 
320     Returns
321     -------
322     ax : matplotlib axes
323         Returns the axes that the rfecv were drawn on.
324     """
325     # Initialize the visualizer
326     oz = RFECV(model, ax=ax, step=step, groups=groups, cv=cv, scoring=scoring)
327 
328     # Fit and poof the visualizer
329     oz.fit(X, y)
330     oz.poof(**kwargs)
331     return oz.ax
332
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/yellowbrick/features/rfecv.py b/yellowbrick/features/rfecv.py
--- a/yellowbrick/features/rfecv.py
+++ b/yellowbrick/features/rfecv.py
@@ -112,6 +112,10 @@
         functions such as ``predict()`` and ``score()`` are passed through to
         this estimator (it rewraps the original model).
 
+    n_feature_subsets_ : array of shape [n_subsets_of_features]
+        The number of features removed on each iteration of RFE, computed by the
+        number of features in the dataset and the step parameter.
+
     Notes
     -----
     This model wraps ``sklearn.feature_selection.RFE`` and not
@@ -172,7 +176,7 @@
 
         # Create the RFE model
         rfe = RFE(self.estimator, step=step)
-        n_feature_subsets = np.arange(1, n_features+1)
+        self.n_feature_subsets_ = np.arange(1, n_features+step, step)
 
         # Create the cross validation params
         # TODO: handle random state
@@ -183,7 +187,7 @@
 
         # Perform cross-validation for each feature subset
         scores = []
-        for n_features_to_select in n_feature_subsets:
+        for n_features_to_select in self.n_feature_subsets_:
             rfe.set_params(n_features_to_select=n_features_to_select)
             scores.append(cross_val_score(rfe, X, y, **cv_params))
 
@@ -192,7 +196,7 @@
 
         # Find the best RFE model
         bestidx = self.cv_scores_.mean(axis=1).argmax()
-        self.n_features_ = n_feature_subsets[bestidx]
+        self.n_features_ = self.n_feature_subsets_[bestidx]
 
         # Fit the final RFE model for the number of features
         self.rfe_estimator_ = rfe
@@ -214,7 +218,7 @@
         Renders the rfecv curve.
         """
         # Compute the curves
-        x = np.arange(1, len(self.cv_scores_)+1)
+        x = self.n_feature_subsets_
         means = self.cv_scores_.mean(axis=1)
         sigmas = self.cv_scores_.std(axis=1)

{"golden_diff": "diff --git a/yellowbrick/features/rfecv.py b/yellowbrick/features/rfecv.py\n--- a/yellowbrick/features/rfecv.py\n+++ b/yellowbrick/features/rfecv.py\n@@ -112,6 +112,10 @@\n         functions such as ``predict()`` and ``score()`` are passed through to\n         this estimator (it rewraps the original model).\n \n+    n_feature_subsets_ : array of shape [n_subsets_of_features]\n+        The number of features removed on each iteration of RFE, computed by the\n+        number of features in the dataset and the step parameter.\n+\n     Notes\n     -----\n     This model wraps ``sklearn.feature_selection.RFE`` and not\n@@ -172,7 +176,7 @@\n \n         # Create the RFE model\n         rfe = RFE(self.estimator, step=step)\n-        n_feature_subsets = np.arange(1, n_features+1)\n+        self.n_feature_subsets_ = np.arange(1, n_features+step, step)\n \n         # Create the cross validation params\n         # TODO: handle random state\n@@ -183,7 +187,7 @@\n \n         # Perform cross-validation for each feature subset\n         scores = []\n-        for n_features_to_select in n_feature_subsets:\n+        for n_features_to_select in self.n_feature_subsets_:\n             rfe.set_params(n_features_to_select=n_features_to_select)\n             scores.append(cross_val_score(rfe, X, y, **cv_params))\n \n@@ -192,7 +196,7 @@\n \n         # Find the best RFE model\n         bestidx = self.cv_scores_.mean(axis=1).argmax()\n-        self.n_features_ = n_feature_subsets[bestidx]\n+        self.n_features_ = self.n_feature_subsets_[bestidx]\n \n         # Fit the final RFE model for the number of features\n         self.rfe_estimator_ = rfe\n@@ -214,7 +218,7 @@\n         Renders the rfecv curve.\n         \"\"\"\n         # Compute the curves\n-        x = np.arange(1, len(self.cv_scores_)+1)\n+        x = self.n_feature_subsets_\n         means = self.cv_scores_.mean(axis=1)\n         sigmas = self.cv_scores_.std(axis=1)\n", "issue": "step: removing 5 features in each iteration\nUsing RFECV, the graph shows best features with one increment in each iteration.\r\nI want to show each iteration should work with an increment of 5 features.\r\nExample: score  should be plotted against x-axis of [5,10,15,20,25].\r\nI used step=5, but its not working.\r\n\r\n\n", "before_files": [{"content": "# yellowbrick.features.rfecv\n# Visualize the number of features selected with recursive feature elimination\n#\n# Author:  Benjamin Bengfort <benjamin@bengfort.com>\n# Created: Tue Apr 03 17:31:37 2018 -0400\n#\n# ID: rfecv.py [] benjamin@bengfort.com $\n\n\"\"\"\nVisualize the number of features selected using recursive feature elimination\n\"\"\"\n\n##########################################################################\n## Imports\n##########################################################################\n\nimport numpy as np\n\nfrom yellowbrick.base import ModelVisualizer\nfrom yellowbrick.exceptions import YellowbrickValueError\n\nfrom sklearn.utils import check_X_y\nfrom sklearn.feature_selection import RFE\nfrom sklearn.model_selection import cross_val_score\n\n\n##########################################################################\n## Recursive Feature Elimination\n##########################################################################\n\nclass RFECV(ModelVisualizer):\n    \"\"\"\n    Recursive Feature Elimination, Cross-Validated (RFECV) feature selection.\n\n    Selects the best subset of features for the supplied estimator by removing\n    0 to N features (where N is the number of features) using recursive\n    feature elimination, then selecting the best subset based on the\n    cross-validation score of the model. Recursive feature elimination\n    eliminates n features from a model by fitting the model multiple times and\n    at each step, removing the weakest features, determined by either the\n    ``coef_`` or ``feature_importances_`` attribute of the fitted model.\n\n    The visualization plots the score relative to each subset and shows trends\n    in feature elimination. If the feature elimination CV score is flat, then\n    potentially there are not enough features in the model. An ideal curve is\n    when the score jumps from low to high as the number of features removed\n    increases, then slowly decreases again from the optimal number of\n    features.\n\n    Parameters\n    ----------\n    model : a scikit-learn estimator\n        An object that implements ``fit`` and provides information about the\n        relative importance of features with either a ``coef_`` or\n        ``feature_importances_`` attribute.\n\n        Note that the object is cloned for each validation.\n\n    ax : matplotlib.Axes object, optional\n        The axes object to plot the figure on.\n\n    step : int or float, optional (default=1)\n        If greater than or equal to 1, then step corresponds to the (integer)\n        number of features to remove at each iteration. If within (0.0, 1.0),\n        then step corresponds to the percentage (rounded down) of features to\n        remove at each iteration.\n\n    groups : array-like, with shape (n_samples,), optional\n        Group labels for the samples used while splitting the dataset into\n        train/test set.\n\n    cv : int, cross-validation generator or an iterable, optional\n        Determines the cross-validation splitting strategy.\n        Possible inputs for cv are:\n\n          - None, to use the default 3-fold cross-validation,\n          - integer, to specify the number of folds.\n          - An object to be used as a cross-validation generator.\n          - An iterable yielding train/test splits.\n\n        see the scikit-learn\n        `cross-validation guide <http://scikit-learn.org/stable/modules/cross_validation.html>`_\n        for more information on the possible strategies that can be used here.\n\n    scoring : string, callable or None, optional, default: None\n        A string or scorer callable object / function with signature\n        ``scorer(estimator, X, y)``. See scikit-learn model evaluation\n        documentation for names of possible metrics.\n\n    kwargs : dict\n        Keyword arguments that are passed to the base class and may influence\n        the visualization as defined in other Visualizers.\n\n    Attributes\n    ----------\n    n_features_ : int\n        The number of features in the selected subset\n\n    support_ : array of shape [n_features]\n        A mask of the selected features\n\n    ranking_ : array of shape [n_features]\n        The feature ranking, such that ``ranking_[i]`` corresponds to the\n        ranked position of feature i. Selected features are assigned rank 1.\n\n    cv_scores_ : array of shape [n_subsets_of_features, n_splits]\n        The cross-validation scores for each subset of features and splits in\n        the cross-validation strategy.\n\n    rfe_estimator_ : sklearn.feature_selection.RFE\n        A fitted RFE estimator wrapping the original estimator. All estimator\n        functions such as ``predict()`` and ``score()`` are passed through to\n        this estimator (it rewraps the original model).\n\n    Notes\n    -----\n    This model wraps ``sklearn.feature_selection.RFE`` and not\n    ``sklearn.feature_selection.RFECV`` because access to the internals of the\n    CV and RFE estimators is required for the visualization. The visualizer\n    does take similar arguments, however it does not expose the same internal\n    attributes.\n\n    Additionally, the RFE model can be accessed via the ``rfe_estimator_``\n    attribute. Once fitted, the visualizer acts as a wrapper for this\n    estimator and not for the original model passed to the model. This way the\n    visualizer model can be used to make predictions.\n\n    .. caution:: This visualizer requires a model that has either a ``coef_``\n        or ``feature_importances_`` attribute when fitted.\n    \"\"\"\n\n    def __init__(self, model, ax=None, step=1, groups=None, cv=None,\n                 scoring=None, **kwargs):\n\n        # Initialize the model visualizer\n        super(RFECV, self).__init__(model, ax=ax, **kwargs)\n\n        # Set parameters\n        self.set_params(step=step, groups=groups, cv=cv, scoring=scoring)\n\n    def fit(self, X, y=None):\n        \"\"\"\n        Fits the RFECV with the wrapped model to the specified data and draws\n        the rfecv curve with the optimal number of features found.\n\n        Parameters\n        ----------\n        X : array-like, shape (n_samples, n_features)\n            Training vector, where n_samples is the number of samples and\n            n_features is the number of features.\n\n        y : array-like, shape (n_samples) or (n_samples, n_features), optional\n            Target relative to X for classification or regression.\n\n        Returns\n        -------\n        self : instance\n            Returns the instance of the RFECV visualizer.\n        \"\"\"\n        X, y = check_X_y(X, y, \"csr\")\n        n_features = X.shape[1]\n\n        # This check is kind of unnecessary since RFE will do it, but it's\n        # nice to get it out of the way ASAP and raise a meaningful error.\n        if 0.0 < self.step < 1.0:\n            step = int(max(1, self.step * n_features))\n        else:\n            step = int(self.step)\n\n        if step < 0:\n            raise YellowbrickValueError(\"step must be >0\")\n\n        # Create the RFE model\n        rfe = RFE(self.estimator, step=step)\n        n_feature_subsets = np.arange(1, n_features+1)\n\n        # Create the cross validation params\n        # TODO: handle random state\n        cv_params = {\n            key: self.get_params()[key]\n            for key in ('groups', 'cv', 'scoring')\n        }\n\n        # Perform cross-validation for each feature subset\n        scores = []\n        for n_features_to_select in n_feature_subsets:\n            rfe.set_params(n_features_to_select=n_features_to_select)\n            scores.append(cross_val_score(rfe, X, y, **cv_params))\n\n        # Convert scores to array\n        self.cv_scores_ = np.array(scores)\n\n        # Find the best RFE model\n        bestidx = self.cv_scores_.mean(axis=1).argmax()\n        self.n_features_ = n_feature_subsets[bestidx]\n\n        # Fit the final RFE model for the number of features\n        self.rfe_estimator_ = rfe\n        self.rfe_estimator_.set_params(n_features_to_select=self.n_features_)\n        self.rfe_estimator_.fit(X, y)\n\n        # Rewrap the visualizer to use the rfe estimator\n        self._wrapped = self.rfe_estimator_\n\n        # Hoist the RFE params to the visualizer\n        self.support_ = self.rfe_estimator_.support_\n        self.ranking_ = self.rfe_estimator_.ranking_\n\n        self.draw()\n        return self\n\n    def draw(self, **kwargs):\n        \"\"\"\n        Renders the rfecv curve.\n        \"\"\"\n        # Compute the curves\n        x = np.arange(1, len(self.cv_scores_)+1)\n        means = self.cv_scores_.mean(axis=1)\n        sigmas = self.cv_scores_.std(axis=1)\n\n\n        # Plot one standard deviation above and below the mean\n        self.ax.fill_between(x, means - sigmas, means+sigmas, alpha=0.25)\n\n        # Plot the curve\n        self.ax.plot(x, means, 'o-')\n\n        # Plot the maximum number of features\n        self.ax.axvline(\n            self.n_features_, c='k', ls='--',\n            label=\"n_features = {}\\nscore = {:0.3f}\".format(\n                self.n_features_, self.cv_scores_.mean(axis=1).max()\n            )\n        )\n\n        return self.ax\n\n    def finalize(self, **kwargs):\n        \"\"\"\n        Add the title, legend, and other visual final touches to the plot.\n        \"\"\"\n        # Set the title of the figure\n        self.set_title('RFECV for {}'.format(self.name))\n\n        # Add the legend\n        self.ax.legend(frameon=True, loc='best')\n\n        # Set the axis labels\n        self.ax.set_xlabel('Number of Features Selected')\n        self.ax.set_ylabel('Score')\n\n\n##########################################################################\n## Quick Methods\n##########################################################################\n\ndef rfecv(model, X, y, ax=None, step=1, groups=None, cv=None,\n          scoring=None, **kwargs):\n    \"\"\"\n    Performs recursive feature elimination with cross-validation to determine\n    an optimal number of features for a model. Visualizes the feature subsets\n    with respect to the cross-validation score.\n\n    This helper function is a quick wrapper to utilize the RFECV visualizer\n    for one-off analysis.\n\n    Parameters\n    ----------\n    model : a scikit-learn estimator\n        An object that implements ``fit`` and provides information about the\n        relative importance of features with either a ``coef_`` or\n        ``feature_importances_`` attribute.\n\n        Note that the object is cloned for each validation.\n\n    X : array-like, shape (n_samples, n_features)\n        Training vector, where n_samples is the number of samples and\n        n_features is the number of features.\n\n    y : array-like, shape (n_samples) or (n_samples, n_features), optional\n        Target relative to X for classification or regression.\n\n    ax : matplotlib.Axes object, optional\n        The axes object to plot the figure on.\n\n    step : int or float, optional (default=1)\n        If greater than or equal to 1, then step corresponds to the (integer)\n        number of features to remove at each iteration. If within (0.0, 1.0),\n        then step corresponds to the percentage (rounded down) of features to\n        remove at each iteration.\n\n    groups : array-like, with shape (n_samples,), optional\n        Group labels for the samples used while splitting the dataset into\n        train/test set.\n\n    cv : int, cross-validation generator or an iterable, optional\n        Determines the cross-validation splitting strategy.\n        Possible inputs for cv are:\n\n          - None, to use the default 3-fold cross-validation,\n          - integer, to specify the number of folds.\n          - An object to be used as a cross-validation generator.\n          - An iterable yielding train/test splits.\n\n        see the scikit-learn\n        `cross-validation guide <http://scikit-learn.org/stable/modules/cross_validation.html>`_\n        for more information on the possible strategies that can be used here.\n\n    scoring : string, callable or None, optional, default: None\n        A string or scorer callable object / function with signature\n        ``scorer(estimator, X, y)``. See scikit-learn model evaluation\n        documentation for names of possible metrics.\n\n    kwargs : dict\n        Keyword arguments that are passed to the base class and may influence\n        the visualization as defined in other Visualizers. These arguments are\n        also passed to the `poof()` method, e.g. can pass a path to save the\n        figure to.\n\n    Returns\n    -------\n    ax : matplotlib axes\n        Returns the axes that the rfecv were drawn on.\n    \"\"\"\n    # Initialize the visualizer\n    oz = RFECV(model, ax=ax, step=step, groups=groups, cv=cv, scoring=scoring)\n\n    # Fit and poof the visualizer\n    oz.fit(X, y)\n    oz.poof(**kwargs)\n    return oz.ax\n", "path": "yellowbrick/features/rfecv.py"}], "after_files": [{"content": "# yellowbrick.features.rfecv\n# Visualize the number of features selected with recursive feature elimination\n#\n# Author:  Benjamin Bengfort <benjamin@bengfort.com>\n# Created: Tue Apr 03 17:31:37 2018 -0400\n#\n# ID: rfecv.py [] benjamin@bengfort.com $\n\n\"\"\"\nVisualize the number of features selected using recursive feature elimination\n\"\"\"\n\n##########################################################################\n## Imports\n##########################################################################\n\nimport numpy as np\n\nfrom yellowbrick.base import ModelVisualizer\nfrom yellowbrick.exceptions import YellowbrickValueError\n\nfrom sklearn.utils import check_X_y\nfrom sklearn.feature_selection import RFE\nfrom sklearn.model_selection import cross_val_score\n\n\n##########################################################################\n## Recursive Feature Elimination\n##########################################################################\n\nclass RFECV(ModelVisualizer):\n    \"\"\"\n    Recursive Feature Elimination, Cross-Validated (RFECV) feature selection.\n\n    Selects the best subset of features for the supplied estimator by removing\n    0 to N features (where N is the number of features) using recursive\n    feature elimination, then selecting the best subset based on the\n    cross-validation score of the model. Recursive feature elimination\n    eliminates n features from a model by fitting the model multiple times and\n    at each step, removing the weakest features, determined by either the\n    ``coef_`` or ``feature_importances_`` attribute of the fitted model.\n\n    The visualization plots the score relative to each subset and shows trends\n    in feature elimination. If the feature elimination CV score is flat, then\n    potentially there are not enough features in the model. An ideal curve is\n    when the score jumps from low to high as the number of features removed\n    increases, then slowly decreases again from the optimal number of\n    features.\n\n    Parameters\n    ----------\n    model : a scikit-learn estimator\n        An object that implements ``fit`` and provides information about the\n        relative importance of features with either a ``coef_`` or\n        ``feature_importances_`` attribute.\n\n        Note that the object is cloned for each validation.\n\n    ax : matplotlib.Axes object, optional\n        The axes object to plot the figure on.\n\n    step : int or float, optional (default=1)\n        If greater than or equal to 1, then step corresponds to the (integer)\n        number of features to remove at each iteration. If within (0.0, 1.0),\n        then step corresponds to the percentage (rounded down) of features to\n        remove at each iteration.\n\n    groups : array-like, with shape (n_samples,), optional\n        Group labels for the samples used while splitting the dataset into\n        train/test set.\n\n    cv : int, cross-validation generator or an iterable, optional\n        Determines the cross-validation splitting strategy.\n        Possible inputs for cv are:\n\n          - None, to use the default 3-fold cross-validation,\n          - integer, to specify the number of folds.\n          - An object to be used as a cross-validation generator.\n          - An iterable yielding train/test splits.\n\n        see the scikit-learn\n        `cross-validation guide <http://scikit-learn.org/stable/modules/cross_validation.html>`_\n        for more information on the possible strategies that can be used here.\n\n    scoring : string, callable or None, optional, default: None\n        A string or scorer callable object / function with signature\n        ``scorer(estimator, X, y)``. See scikit-learn model evaluation\n        documentation for names of possible metrics.\n\n    kwargs : dict\n        Keyword arguments that are passed to the base class and may influence\n        the visualization as defined in other Visualizers.\n\n    Attributes\n    ----------\n    n_features_ : int\n        The number of features in the selected subset\n\n    support_ : array of shape [n_features]\n        A mask of the selected features\n\n    ranking_ : array of shape [n_features]\n        The feature ranking, such that ``ranking_[i]`` corresponds to the\n        ranked position of feature i. Selected features are assigned rank 1.\n\n    cv_scores_ : array of shape [n_subsets_of_features, n_splits]\n        The cross-validation scores for each subset of features and splits in\n        the cross-validation strategy.\n\n    rfe_estimator_ : sklearn.feature_selection.RFE\n        A fitted RFE estimator wrapping the original estimator. All estimator\n        functions such as ``predict()`` and ``score()`` are passed through to\n        this estimator (it rewraps the original model).\n\n    n_feature_subsets_ : array of shape [n_subsets_of_features]\n        The number of features removed on each iteration of RFE, computed by the\n        number of features in the dataset and the step parameter.\n\n    Notes\n    -----\n    This model wraps ``sklearn.feature_selection.RFE`` and not\n    ``sklearn.feature_selection.RFECV`` because access to the internals of the\n    CV and RFE estimators is required for the visualization. The visualizer\n    does take similar arguments, however it does not expose the same internal\n    attributes.\n\n    Additionally, the RFE model can be accessed via the ``rfe_estimator_``\n    attribute. Once fitted, the visualizer acts as a wrapper for this\n    estimator and not for the original model passed to the model. This way the\n    visualizer model can be used to make predictions.\n\n    .. caution:: This visualizer requires a model that has either a ``coef_``\n        or ``feature_importances_`` attribute when fitted.\n    \"\"\"\n\n    def __init__(self, model, ax=None, step=1, groups=None, cv=None,\n                 scoring=None, **kwargs):\n\n        # Initialize the model visualizer\n        super(RFECV, self).__init__(model, ax=ax, **kwargs)\n\n        # Set parameters\n        self.set_params(step=step, groups=groups, cv=cv, scoring=scoring)\n\n    def fit(self, X, y=None):\n        \"\"\"\n        Fits the RFECV with the wrapped model to the specified data and draws\n        the rfecv curve with the optimal number of features found.\n\n        Parameters\n        ----------\n        X : array-like, shape (n_samples, n_features)\n            Training vector, where n_samples is the number of samples and\n            n_features is the number of features.\n\n        y : array-like, shape (n_samples) or (n_samples, n_features), optional\n            Target relative to X for classification or regression.\n\n        Returns\n        -------\n        self : instance\n            Returns the instance of the RFECV visualizer.\n        \"\"\"\n        X, y = check_X_y(X, y, \"csr\")\n        n_features = X.shape[1]\n\n        # This check is kind of unnecessary since RFE will do it, but it's\n        # nice to get it out of the way ASAP and raise a meaningful error.\n        if 0.0 < self.step < 1.0:\n            step = int(max(1, self.step * n_features))\n        else:\n            step = int(self.step)\n\n        if step < 0:\n            raise YellowbrickValueError(\"step must be >0\")\n\n        # Create the RFE model\n        rfe = RFE(self.estimator, step=step)\n        self.n_feature_subsets_ = np.arange(1, n_features+step, step)\n\n        # Create the cross validation params\n        # TODO: handle random state\n        cv_params = {\n            key: self.get_params()[key]\n            for key in ('groups', 'cv', 'scoring')\n        }\n\n        # Perform cross-validation for each feature subset\n        scores = []\n        for n_features_to_select in self.n_feature_subsets_:\n            rfe.set_params(n_features_to_select=n_features_to_select)\n            scores.append(cross_val_score(rfe, X, y, **cv_params))\n\n        # Convert scores to array\n        self.cv_scores_ = np.array(scores)\n\n        # Find the best RFE model\n        bestidx = self.cv_scores_.mean(axis=1).argmax()\n        self.n_features_ = self.n_feature_subsets_[bestidx]\n\n        # Fit the final RFE model for the number of features\n        self.rfe_estimator_ = rfe\n        self.rfe_estimator_.set_params(n_features_to_select=self.n_features_)\n        self.rfe_estimator_.fit(X, y)\n\n        # Rewrap the visualizer to use the rfe estimator\n        self._wrapped = self.rfe_estimator_\n\n        # Hoist the RFE params to the visualizer\n        self.support_ = self.rfe_estimator_.support_\n        self.ranking_ = self.rfe_estimator_.ranking_\n\n        self.draw()\n        return self\n\n    def draw(self, **kwargs):\n        \"\"\"\n        Renders the rfecv curve.\n        \"\"\"\n        # Compute the curves\n        x = self.n_feature_subsets_\n        means = self.cv_scores_.mean(axis=1)\n        sigmas = self.cv_scores_.std(axis=1)\n\n\n        # Plot one standard deviation above and below the mean\n        self.ax.fill_between(x, means - sigmas, means+sigmas, alpha=0.25)\n\n        # Plot the curve\n        self.ax.plot(x, means, 'o-')\n\n        # Plot the maximum number of features\n        self.ax.axvline(\n            self.n_features_, c='k', ls='--',\n            label=\"n_features = {}\\nscore = {:0.3f}\".format(\n                self.n_features_, self.cv_scores_.mean(axis=1).max()\n            )\n        )\n\n        return self.ax\n\n    def finalize(self, **kwargs):\n        \"\"\"\n        Add the title, legend, and other visual final touches to the plot.\n        \"\"\"\n        # Set the title of the figure\n        self.set_title('RFECV for {}'.format(self.name))\n\n        # Add the legend\n        self.ax.legend(frameon=True, loc='best')\n\n        # Set the axis labels\n        self.ax.set_xlabel('Number of Features Selected')\n        self.ax.set_ylabel('Score')\n\n\n##########################################################################\n## Quick Methods\n##########################################################################\n\ndef rfecv(model, X, y, ax=None, step=1, groups=None, cv=None,\n          scoring=None, **kwargs):\n    \"\"\"\n    Performs recursive feature elimination with cross-validation to determine\n    an optimal number of features for a model. Visualizes the feature subsets\n    with respect to the cross-validation score.\n\n    This helper function is a quick wrapper to utilize the RFECV visualizer\n    for one-off analysis.\n\n    Parameters\n    ----------\n    model : a scikit-learn estimator\n        An object that implements ``fit`` and provides information about the\n        relative importance of features with either a ``coef_`` or\n        ``feature_importances_`` attribute.\n\n        Note that the object is cloned for each validation.\n\n    X : array-like, shape (n_samples, n_features)\n        Training vector, where n_samples is the number of samples and\n        n_features is the number of features.\n\n    y : array-like, shape (n_samples) or (n_samples, n_features), optional\n        Target relative to X for classification or regression.\n\n    ax : matplotlib.Axes object, optional\n        The axes object to plot the figure on.\n\n    step : int or float, optional (default=1)\n        If greater than or equal to 1, then step corresponds to the (integer)\n        number of features to remove at each iteration. If within (0.0, 1.0),\n        then step corresponds to the percentage (rounded down) of features to\n        remove at each iteration.\n\n    groups : array-like, with shape (n_samples,), optional\n        Group labels for the samples used while splitting the dataset into\n        train/test set.\n\n    cv : int, cross-validation generator or an iterable, optional\n        Determines the cross-validation splitting strategy.\n        Possible inputs for cv are:\n\n          - None, to use the default 3-fold cross-validation,\n          - integer, to specify the number of folds.\n          - An object to be used as a cross-validation generator.\n          - An iterable yielding train/test splits.\n\n        see the scikit-learn\n        `cross-validation guide <http://scikit-learn.org/stable/modules/cross_validation.html>`_\n        for more information on the possible strategies that can be used here.\n\n    scoring : string, callable or None, optional, default: None\n        A string or scorer callable object / function with signature\n        ``scorer(estimator, X, y)``. See scikit-learn model evaluation\n        documentation for names of possible metrics.\n\n    kwargs : dict\n        Keyword arguments that are passed to the base class and may influence\n        the visualization as defined in other Visualizers. These arguments are\n        also passed to the `poof()` method, e.g. can pass a path to save the\n        figure to.\n\n    Returns\n    -------\n    ax : matplotlib axes\n        Returns the axes that the rfecv were drawn on.\n    \"\"\"\n    # Initialize the visualizer\n    oz = RFECV(model, ax=ax, step=step, groups=groups, cv=cv, scoring=scoring)\n\n    # Fit and poof the visualizer\n    oz.fit(X, y)\n    oz.poof(**kwargs)\n    return oz.ax\n", "path": "yellowbrick/features/rfecv.py"}]}