Repository: nilearn/nilearn

Issue:
Add warning when calculated n_parcels does not match requested n_parcels
<!--
Hi! 
If you have: 
 -1 Questions about how to use Nilearn or 
 -2 Need analysis suggestions & recommendations?

A bunch of fMRI researchers hang out at Neurostars (http://neurostars.org/). 
Post those questions there. 
Add the tag `nilearn` (we get an email from Neurostars if you do).

Posting them here makes life more complicated for the Nilearn developers.  
-->

<!-- 
For the Feature Request,
Include the following:
------------------------
What would you like changed/added and why?
What would be the benefit? Does the change make something easier to use?
Clarifies something?
If it is a new feature, what is the benefit? 
-->

In the `Parcellations` class, users can provide [a desired n_parcels](https://github.com/nilearn/nilearn/blob/5b7648cc4d452389f2d9320fafdfd1aa27562c0e/nilearn/regions/parcellations.py#L133) that they would like to be learned. I've noticed that sometimes &mdash; particularly, it seems, with k-means &mdash; the number of learned parcels does not exactly match the number of desired parcels. 

This can cause problems with downstream uses, such as in [fmralign](https://github.com/parietal-INRIA/fmralign). I'd like to add a check and to the `Parcellations` class that confirms that the learned number of parcels matches `n_parcels` and raises a warning if it does not.

WDYT ?



Discussion:

Resolving patch:
diff --git a/nilearn/regions/parcellations.py b/nilearn/regions/parcellations.py
--- a/nilearn/regions/parcellations.py
+++ b/nilearn/regions/parcellations.py
@@ -1,6 +1,7 @@
 """Parcellation tools such as KMeans or Ward for fMRI images
 """
 
+import warnings
 import numpy as np
 
 from sklearn.base import clone
@@ -366,6 +367,14 @@ def _raw_fit(self, data):
             self.connectivity_ = connectivity
         # Avoid 0 label
         labels = labels + 1
+        unique_labels = np.unique(labels)
+
+        # Check that appropriate number of labels were created
+        if len(unique_labels) != self.n_parcels:
+            n_parcels_warning = ('The number of generated labels does not '
+                                 'match the requested number of parcels.')
+            warnings.warn(message=n_parcels_warning, category=UserWarning,
+                          stacklevel=3)
         self.labels_img_ = self.masker_.inverse_transform(labels)
 
         return self


Test patch:
diff --git a/nilearn/regions/tests/test_parcellations.py b/nilearn/regions/tests/test_parcellations.py
--- a/nilearn/regions/tests/test_parcellations.py
+++ b/nilearn/regions/tests/test_parcellations.py
@@ -4,6 +4,7 @@
 import numpy as np
 import nibabel
 
+import pytest
 from nose.tools import assert_true, assert_equal
 from nilearn.regions.parcellations import (Parcellations,
                                            _check_parameters_transform)
@@ -60,6 +61,23 @@ def test_parcellations_fit_on_single_nifti_image():
                                            data.shape[2]))
 
 
+def test_parcellations_warnings():
+    data = np.zeros((10, 11, 12, 5))
+    img = nibabel.Nifti1Image(data, affine=np.eye(4))
+    parcellator = Parcellations(method='kmeans', n_parcels=7)
+    with pytest.warns(UserWarning):
+        parcellator.fit(img)
+
+
+def test_parcellations_no_warnings():
+    data = np.zeros((10, 11, 12, 5))
+    img = nibabel.Nifti1Image(data, affine=np.eye(4))
+    parcellator = Parcellations(method='kmeans', n_parcels=1)
+    with pytest.warns(None) as record:
+        parcellator.fit(img)
+    assert all([r.category is not UserWarning for r in record.list])
+
+
 def test_parcellations_fit_on_multi_nifti_images():
     data = np.zeros((10, 11, 12, 5))
     data[9, 10, 2] = 1