From 0bf053fbeb8cb9d498027c9a2151e8c812fd7a77 Mon Sep 17 00:00:00 2001
From: Alexandre Gramfort <alexandre.gramfort@inria.fr>
Date: Thu, 24 Feb 2011 17:44:31 -0500
Subject: [PATCH] FIX : fixing Lars lasso with early stopping using alph_min +
 adding test for it

---
 scikits/learn/linear_model/least_angle.py     | 19 +++++++++++--------
 .../linear_model/tests/test_least_angle.py    | 16 ++++++++++++++++
 2 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/scikits/learn/linear_model/least_angle.py b/scikits/learn/linear_model/least_angle.py
index 6739451a22..affb85fa67 100644
--- a/scikits/learn/linear_model/least_angle.py
+++ b/scikits/learn/linear_model/least_angle.py
@@ -120,7 +120,17 @@ def lars_path(X, y, Xy=None, Gram=None, max_features=None,
 
         alphas[n_iter] = C / n_samples
 
-        if (C < alpha_min) or (n_active == max_features):
+        # Check for early stopping
+        if alphas[n_iter] < alpha_min: # interpolate
+            # interpolation factor 0 <= ss < 1
+            ss = (alphas[n_iter-1] - alpha_min) / (alphas[n_iter-1] -
+                                                   alphas[n_iter])
+            coefs[n_iter] = coefs[n_iter-1] + ss*(coefs[n_iter] -
+                            coefs[n_iter-1])
+            alphas[n_iter] = alpha_min
+            break
+
+        if n_active == max_features:
             break
 
         if not drop:
@@ -270,13 +280,6 @@ def lars_path(X, y, Xy=None, Gram=None, max_features=None,
             if verbose:
                 print "%s\t\t%s\t\t%s\t\t%s\t\t%s" % (n_iter, '', drop_idx,
                                                       n_active, abs(temp))
-    if alphas[n_iter] < alpha_min: # interpolate
-        # interpolation factor 0 <= ss < 1
-        ss = (alphas[n_iter-1] - alpha_min) / (alphas[n_iter-1] -
-                                               alphas[n_iter])
-        coefs[n_iter] = coefs[n_iter-1] + ss*(coefs[n_iter] - coefs[n_iter-1])
-        alphas[n_iter] = alpha_min
-        
 
     # resize coefs in case of early stop
     alphas = alphas[:n_iter+1]
diff --git a/scikits/learn/linear_model/tests/test_least_angle.py b/scikits/learn/linear_model/tests/test_least_angle.py
index c9bf228ca4..4521dbbab5 100644
--- a/scikits/learn/linear_model/tests/test_least_angle.py
+++ b/scikits/learn/linear_model/tests/test_least_angle.py
@@ -111,6 +111,22 @@ def test_lasso_lars_vs_lasso_cd(verbose=False):
         error = np.linalg.norm(c - lasso_cd.coef_)
         assert error < 0.01
 
+def test_lasso_lars_vs_lasso_cd_early_stopping(verbose=False):
+    """
+    Test that LassoLars and Lasso using coordinate descent give the
+    same results when early stopping is used.
+    (test : before, in the middle, and in the last part of the path)
+    """
+    alphas_min = [10, 0.9, 1e-4]
+    for alphas_min in alphas_min:
+        alphas, _, lasso_path = linear_model.lars_path(X, y, method='lasso',
+                                                    alpha_min=0.9)
+        lasso_cd = linear_model.Lasso(fit_intercept=False)
+        lasso_cd.alpha = alphas[-1]
+        lasso_cd.fit(X, y, tol=1e-8)
+        error = np.linalg.norm(lasso_path[:,-1] - lasso_cd.coef_)
+        assert error < 0.01
+
 
 if __name__ == '__main__':
     import nose
-- 
GitLab