Repository: nilearn/nilearn

Issue:
signal.clean with standardize=False
The behavior of signal.clean with standardize=False is different whether one includes or not confounds. If confounds to remove, the input signal and the confounds are standardized even though standardize=False.

The standard choice for scaling signals within ROIs (e.g. MarsBaR, Conn) is to scale them to their own ROI-specific average BOLD signal and multiply by 100 to get what is commonly called Percent Signal Change units. This allows to put all the ROIs to the same range while maintaining the difference in variances between them. 

Below signals within 2 ROIs from ADHD dataset, note that although region 12 has higher average, it has less variance. But after the regression of one confound (average CSF), the variances are almost the same because of this partial standardization achieved in signal.clean. My expected behavior of cleaning is the bottom subplot.

![demo_psc](https://cloud.githubusercontent.com/assets/7080143/7209880/0574f630-e54d-11e4-883b-7aeb35fd4759.png)



Discussion:
Sorry but the range in the cleaned PSC subplot was incorrect, this is the correct one.

![demo_psc](https://cloud.githubusercontent.com/assets/7080143/7218715/8eef503c-e67d-11e4-8291-32c5334bedcf.png)

I think that we have a bug here: the fact that with confounds, the variance of the signal is forgotten is wrong.

I remember that Philippe divided by the standard variance before removing the confounds to give a better conditioning to the confound regression. What we should do is probably multiply back by the standard deviation after confound removal.

Hum, thinking more closely about this, I think that the standardization of the signal is not useful to improve conditioning of confound removal, only that of the confounds.


Resolving patch:
diff --git a/nilearn/signal.py b/nilearn/signal.py
--- a/nilearn/signal.py
+++ b/nilearn/signal.py
@@ -408,14 +408,9 @@ def clean(signals, detrend=True, standardize=True, confounds=None,
                       (list, tuple, _basestring, np.ndarray, type(None))):
         raise TypeError("confounds keyword has an unhandled type: %s"
                         % confounds.__class__)
-    # Standardize / detrend
-    normalize = False
-    if confounds is not None:
-        # If confounds are to be removed, then force normalization to improve
-        # matrix conditioning.
-        normalize = True
+    # detrend
     signals = _ensure_float(signals)
-    signals = _standardize(signals, normalize=normalize, detrend=detrend)
+    signals = _standardize(signals, normalize=False, detrend=detrend)
 
     # Remove confounds
     if confounds is not None:


Test patch:
diff --git a/nilearn/tests/test_signal.py b/nilearn/tests/test_signal.py
--- a/nilearn/tests/test_signal.py
+++ b/nilearn/tests/test_signal.py
@@ -279,7 +279,7 @@ def test_clean_confounds():
     # With signal: output must be orthogonal to confounds
     cleaned_signals = nisignal.clean(signals + noises, confounds=confounds,
                                       detrend=True, standardize=False)
-    assert_true(abs(np.dot(confounds.T, cleaned_signals)).max() < 100. * eps)
+    assert_true(abs(np.dot(confounds.T, cleaned_signals)).max() < 1000. * eps)
 
     # Test detrending. No trend should exist in the output.
     # Use confounds with a trend.
@@ -296,7 +296,7 @@ def test_clean_confounds():
                                       detrend=True, standardize=False)
     coeffs = np.polyfit(np.arange(cleaned_signals.shape[0]),
                         cleaned_signals, 1)
-    assert_true((abs(coeffs) < 10. * eps).all())  # trend removed
+    assert_true((abs(coeffs) < 100. * eps).all())  # trend removed
 
     # Test no-op
     input_signals = 10 * signals