Repository: DistrictDataLabs/yellowbrick

Issue:
FeatureImportances stack documentation
Thank you so much @zjpoh for enhancing the `FeatureImportance` visualizer with a stack bar chart! There are a couple of minor tasks to complete that I will take care of in the next couple of days:

1. Add documentation about the stack argument and the implications 
2. Add `skipif` pandas not available, or non-pandas testing 
3. When stack gets set to False, issue warning about what happened 
4. Non-classifier multi-output regressors test 

See #492 and #510 


Discussion:
@bbengfort thanks for filling in the gaps of my PR. I will take a look at what you add and hopefully next time I can have a more complete PR. =)
@zjpoh your PR was absolutely complete in every respect! We try to do things in iterative, small, incremental steps so that we don't overload the PR process or exhaust our contributors. As YB has gotten bigger, there is just a lot of stuff from documentation to checks, CI, dependencies etc. that we have to manage. It's kind of drudge work and just has to be done in order to make the package accessible and intuitive. Please keep submitting PRs and if you'd like to take on some of these other maintenance tasks, we'd be happy to have those types of contributions also! 

I'm sorry if I made you feel that your PR wasn't sufficient - it was great and a welcome addition to Yellowbrick! 

RE @DistrictDataLabs/team-oz-maintainers 

Resolving patch:
diff --git a/docs/api/features/importances.py b/docs/api/features/importances.py
--- a/docs/api/features/importances.py
+++ b/docs/api/features/importances.py
@@ -4,7 +4,8 @@
 
 from yellowbrick.features.importances import FeatureImportances
 from sklearn.ensemble import GradientBoostingClassifier
-from sklearn.linear_model import Lasso
+from sklearn.linear_model import Lasso, LogisticRegression
+from sklearn.datasets import load_iris
 
 
 DATA_DIR = os.path.relpath(os.path.join(
@@ -46,6 +47,18 @@ def coef_(outpath):
     viz.poof(outpath=outpath)
 
 
+def stacked_coef_(outpath):
+    data = load_iris()
+
+    fig = plt.figure()
+    ax = fig.add_subplot()
+
+    viz = FeatureImportances(LogisticRegression(), ax=ax, stack=True, relative=False)
+    viz.fit(data.data, data.target)
+    viz.poof(outpath=outpath)
+
+
 if __name__ == '__main__':
-    feature_importances_("images/feature_importances.png")
-    coef_("images/feature_importances_coef.png")
+    # feature_importances_("images/feature_importances.png")
+    # coef_("images/feature_importances_coef.png")
+    stacked_coef_("images/feature_importances_stacked.png")
\ No newline at end of file
diff --git a/yellowbrick/features/importances.py b/yellowbrick/features/importances.py
--- a/yellowbrick/features/importances.py
+++ b/yellowbrick/features/importances.py
@@ -21,13 +21,14 @@
 ## Imports
 ##########################################################################
 
+import warnings
 import numpy as np
 import matplotlib.pyplot as plt
 
-from yellowbrick.utils import is_dataframe, is_classifier
 from yellowbrick.base import ModelVisualizer
-from yellowbrick.exceptions import YellowbrickTypeError, NotFitted
-from ..style.palettes import color_palette
+from yellowbrick.style.palettes import color_palette
+from yellowbrick.utils import is_dataframe, is_classifier
+from yellowbrick.exceptions import YellowbrickTypeError, NotFitted, YellowbrickWarning
 
 
 ##########################################################################
@@ -150,8 +151,11 @@ def fit(self, X, y=None, **kwargs):
         # therefore we flatten by taking the average by
         # column to get shape (n_features,)  (see LogisticRegression)
         if not self.stack and self.feature_importances_.ndim > 1:
-            self.feature_importances_ = np.mean(self.feature_importances_,
-                                                axis=0)
+            self.feature_importances_ = np.mean(self.feature_importances_, axis=0)
+            warnings.warn((
+                "detected multi-dimensional feature importances but stack=False, "
+                "using mean to aggregate them."
+            ), YellowbrickWarning)
 
         # Apply absolute value filter before normalization
         if self.absolute:


Test patch:
diff --git a/tests/baseline_images/test_features/test_importances/test_multi_coefs_stacked.png b/tests/baseline_images/test_features/test_importances/test_multi_coefs_stacked.png
Binary files a/tests/baseline_images/test_features/test_importances/test_multi_coefs_stacked.png and b/tests/baseline_images/test_features/test_importances/test_multi_coefs_stacked.png differ
diff --git a/tests/test_features/test_importances.py b/tests/test_features/test_importances.py
--- a/tests/test_features/test_importances.py
+++ b/tests/test_features/test_importances.py
@@ -230,7 +230,7 @@ def test_fit_absolute(self):
 
     def test_multi_coefs(self):
         """
-        Test fit with multidimensional coefficients
+        Test fit with multidimensional coefficients and stack warning
         """
         coefs = np.array([
             [0.4, 0.2, -0.08, 0.07, 0.16, 0.23, -0.38, 0.1, -0.05],
@@ -242,10 +242,12 @@ def test_multi_coefs(self):
         model = MockEstimator()
         model.make_importance_param(value=coefs)
 
-        visualizer = FeatureImportances(model)
-        visualizer.fit(
-            np.random.rand(100, len(np.mean(coefs, axis=0))), np.random.rand(100)
-        )
+        visualizer = FeatureImportances(model, stack=False)
+
+        with pytest.warns(YellowbrickWarning):
+            visualizer.fit(
+                np.random.rand(100, len(np.mean(coefs, axis=0))), np.random.rand(100)
+            )
 
         npt.assert_equal(visualizer.feature_importances_.ndim, 1)
 
@@ -256,12 +258,11 @@ def test_multi_coefs_stacked(self):
         """
         Test stack plot with multidimensional coefficients
         """
-        X_iris, y_iris = load_iris(True)
-        X_iris_pd = pd.DataFrame(X_iris, columns=['f1', 'f2', 'f3', 'f4'])
+        X, y = load_iris(True)
 
-        viz = FeatureImportances(LogisticRegression(), stack=True)
-        viz.fit(X_iris_pd, y_iris)
-        viz.poof()
+        viz = FeatureImportances(LogisticRegression(random_state=222), stack=True)
+        viz.fit(X, y)
+        viz.finalize()
 
         npt.assert_equal(viz.feature_importances_.shape, (3, 4))
         self.assert_images_similar(viz)