Skip to content

Commit 02835da

Browse files
committed
add CQR_Ridge_path_sol
1 parent b80d7fa commit 02835da

File tree

1 file changed

+132
-14
lines changed

1 file changed

+132
-14
lines changed

rehline/_path_sol.py

Lines changed: 132 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import time
22

3-
import matplotlib.pyplot as plt
43
import numpy as np
54

65
from ._base import _make_loss_rehline_param
76
from ._class import plqERM_Ridge
7+
from ._class import CQR_Ridge
88
from ._loss import ReHLoss
99

1010

@@ -215,22 +215,140 @@ def plqERM_Ridge_path_sol(
215215
print(f"{'Avg Time/Iter':<12}{avg_time_per_iter:.6f} sec")
216216
print("=" * 90)
217217

218-
# ben: remove the plot part, when d is large, the figure will be too large to show
219-
# if verbose >= 2:
220-
# # it's better to load the matplotlib.pyplot before the function
221-
# import matplotlib.pyplot as plt
222-
# plt.figure(figsize=(10, 6))
223-
# for i in range(n_features):
224-
# plt.plot(Cs, coefs[i, :], label=f'Feature {i+1}')
225-
# plt.xscale('log')
226-
# plt.xlabel('C')
227-
# plt.ylabel('Coefficient Value')
228-
# plt.title('Regularization Path')
229-
# plt.legend()
230-
# plt.show()
231218

232219
if return_time:
233220
return Cs, times, n_iters, obj_values, L2_norms, coefs
234221
else:
235222
return Cs, n_iters, obj_values, L2_norms, coefs
236223

224+
225+
226+
def CQR_Ridge_path_sol(
227+
X,
228+
y,
229+
*,
230+
quantiles,
231+
eps=1e-5,
232+
n_Cs=50,
233+
Cs=None,
234+
max_iter=5000,
235+
tol=1e-4,
236+
verbose=0,
237+
shrink=1,
238+
warm_start=False,
239+
return_time=True,
240+
):
241+
"""
242+
Compute the regularization path for Composite Quantile Regression (CQR) with ridge penalty.
243+
244+
This function fits a series of CQR models using different values of the regularization parameter `C`.
245+
It reuses a single estimator and modifies `C` in-place before refitting.
246+
247+
Parameters
248+
----------
249+
X : ndarray of shape (n_samples, n_features)
250+
Feature matrix.
251+
252+
y : ndarray of shape (n_samples,)
253+
Response vector.
254+
255+
quantiles : list of float
256+
Quantile levels (e.g. [0.1, 0.5, 0.9]).
257+
258+
eps : float, default=1e-5
259+
Log-scaled lower bound for generated `C` values (used if `Cs` is None).
260+
261+
n_Cs : int, default=50
262+
Number of `C` values to generate.
263+
264+
Cs : array-like or None, default=None
265+
Explicit values of regularization strength. If None, use `eps` and `n_Cs` to generate them.
266+
267+
max_iter : int, default=5000
268+
Maximum number of solver iterations.
269+
270+
tol : float, default=1e-4
271+
Solver convergence tolerance.
272+
273+
verbose : int, default=0
274+
Verbosity level.
275+
276+
shrink : float, default=1
277+
Shrinkage parameter passed to solver.
278+
279+
warm_start : bool, default=False
280+
Use previous dual solution to initialize the next fit.
281+
282+
return_time : bool, default=True
283+
Whether to return a list of fit durations.
284+
285+
Returns
286+
-------
287+
Cs : ndarray
288+
List of regularization strengths.
289+
290+
models : list
291+
List of fitted model objects.
292+
293+
coefs : ndarray of shape (n_Cs, n_quantiles, n_features)
294+
Coefficient matrices per quantile and `C`.
295+
296+
intercepts : ndarray of shape (n_Cs, n_quantiles)
297+
Intercepts per quantile and `C`.
298+
299+
fit_times : list of float, optional
300+
Elapsed fit times (if `return_time=True`).
301+
"""
302+
303+
if Cs is None:
304+
log_Cs = np.linspace(np.log10(eps), np.log10(10), n_Cs)
305+
Cs = np.power(10.0, log_Cs)
306+
else:
307+
Cs = np.array(Cs)
308+
309+
models = []
310+
fit_times = []
311+
coefs = []
312+
intercepts = []
313+
314+
clf = CQR_Ridge(
315+
quantiles=quantiles,
316+
C=Cs[0],
317+
max_iter=max_iter,
318+
tol=tol,
319+
shrink=shrink,
320+
verbose=verbose,
321+
warm_start=warm_start,
322+
)
323+
324+
for i, C in enumerate(Cs):
325+
clf.C = C
326+
327+
if return_time:
328+
start = time.time()
329+
330+
clf.fit(X, y)
331+
332+
d = X.shape[1]
333+
n_qt = len(quantiles)
334+
335+
coef_matrix = np.tile(clf.coef_, (n_qt, 1))
336+
intercept_vector = clf.intercept_
337+
338+
models.append(clf)
339+
coefs.append(coef_matrix)
340+
intercepts.append(intercept_vector)
341+
342+
if return_time:
343+
elapsed = time.time() - start
344+
fit_times.append(elapsed)
345+
if verbose >= 1:
346+
print(f"[OK] C={C:.3e}, time={elapsed:.3f}s")
347+
348+
coefs = np.array(coefs) # (n_Cs, n_quantiles, n_features)
349+
intercepts = np.array(intercepts) # (n_Cs, n_quantiles)
350+
351+
if return_time:
352+
return Cs, models, coefs, intercepts, fit_times
353+
else:
354+
return Cs, models, coefs, intercepts

0 commit comments

Comments
 (0)