Skip to content

Commit 6afdeb9

Browse files
committed
update of codes for week 37
1 parent abd1d73 commit 6afdeb9

File tree

2 files changed

+130
-30
lines changed

2 files changed

+130
-30
lines changed

doc/Programs/Regression/lasso.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
4+
class LassoGD:
5+
def __init__(self, lr=0.01, l1_penalty=1.0, tol=1e-6, max_iter=1000):
6+
"""Initialize LASSO regressor with given hyperparameters."""
7+
self.lr = lr # learning rate (step size)
8+
self.l1_penalty = l1_penalty # L1 regularization strength (λ)
9+
self.tol = tol # convergence tolerance for change in cost
10+
self.max_iter = max_iter # maximum iterations to run
11+
self.weights = None # model weights (including intercept as w[0])
12+
self.feature_means = None # to store feature means for normalization
13+
self.feature_stds = None # to store feature std devs for normalization
14+
self.cost_history = None # to record cost at each iteration
15+
16+
def fit(self, X, y, normalize=True):
17+
"""Train the LASSO model on data X (shape m x n) and targets y (length m)."""
18+
X = np.array(X, dtype=float)
19+
y = np.array(y, dtype=float)
20+
m, n = X.shape
21+
# 1. Feature normalization (zero mean, unit variance)
22+
if normalize:
23+
self.feature_means = X.mean(axis=0)
24+
self.feature_stds = X.std(axis=0)
25+
self.feature_stds[self.feature_stds == 0] = 1.0 # avoid division by zero
26+
X = (X - self.feature_means) / self.feature_stds
27+
else:
28+
# If not normalizing, set means=0 and stds=1 for consistency
29+
self.feature_means = np.zeros(n)
30+
self.feature_stds = np.ones(n)
31+
# Add bias term (intercept) as an extra column of ones in X
32+
X_bias = np.hstack([np.ones((m, 1)), X])
33+
# Initialize weights (n features + 1 intercept) to zero
34+
self.weights = np.zeros(n + 1)
35+
self.cost_history = []
36+
37+
prev_cost = float('inf')
38+
# Gradient Descent Loop
39+
for it in range(self.max_iter):
40+
# 2. Predictions for current weights
41+
y_pred = X_bias.dot(self.weights)
42+
error = y_pred - y
43+
# 3. Compute cost = MSE + L1 penalty (do not penalize intercept w[0])
44+
mse_cost = (error ** 2).mean() / 2.0
45+
l1_cost = self.l1_penalty * np.sum(np.abs(self.weights[1:]))
46+
cost = mse_cost + l1_cost
47+
self.cost_history.append(cost)
48+
# Check convergence: stop if change in cost is below tolerance
49+
if abs(prev_cost - cost) < self.tol:
50+
break
51+
prev_cost = cost
52+
# 4. Compute gradient of MSE part
53+
grad_mse = (X_bias.T.dot(error)) / m # gradient of 1/(2m)*RSS is X^T(error)/m
54+
# 5. Perform gradient descent update with L1 penalty via soft-thresholding
55+
# Take a gradient step for MSE
56+
w_temp = self.weights - self.lr * grad_mse
57+
# Soft-thresholding for L1: shrink weights toward 0 by lr*λ
58+
thresh = self.lr * self.l1_penalty
59+
w0 = w_temp[0] # intercept (no regularization)
60+
w_rest = w_temp[1:]
61+
# Apply soft threshold to each weight in w_rest
62+
w_rest_updated = np.sign(w_rest) * np.maximum(np.abs(w_rest) - thresh, 0.0)
63+
# Update weights (combine intercept and rest)
64+
self.weights = np.concatenate(([w0], w_rest_updated))
65+
# End of gradient descent loop
66+
67+
def predict(self, X):
68+
"""Make predictions using the trained model on new data X."""
69+
X = np.array(X, dtype=float)
70+
# Normalize using the training mean and std
71+
X_norm = (X - self.feature_means) / self.feature_stds
72+
# Add bias term
73+
X_bias = np.hstack([np.ones((X_norm.shape[0], 1)), X_norm])
74+
return X_bias.dot(self.weights)
75+
76+
# --- Example usage on a synthetic dataset ---
77+
np.random.seed(0)
78+
# Create synthetic data: m samples, n features
79+
m, n = 100, 5
80+
X = np.random.randn(m, n)
81+
# True underlying weights for features (some are zero to illustrate feature selection)
82+
true_w = np.array([0, 0, 5, 0, -3], dtype=float)
83+
true_intercept = 10.0
84+
# Generate targets with a linear combination of X and noise
85+
y = true_intercept + X.dot(true_w) + 0.5 * np.random.randn(m)
86+
87+
# Train LASSO regression model
88+
model = LassoGD(lr=0.05, l1_penalty=0.5, tol=1e-6, max_iter=1000)
89+
model.fit(X, y)
90+
print("Learned weights (intercept + coefficients):", model.weights)
91+
92+
# Plot the cost function history over iterations
93+
plt.figure(figsize=(6,4))
94+
plt.plot(model.cost_history, label="Cost")
95+
plt.title("Cost Function Value vs Iterations")
96+
plt.xlabel("Iteration")
97+
plt.ylabel("Cost (MSE + L1 penalty)")
98+
plt.legend()
99+
plt.grid(True)
100+
plt.show()

doc/Programs/Regression/ooreg.py

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,71 +19,71 @@ def save_csv(filename, X, y_true, y_pred):
1919

2020
class LinearRegression:
2121
def __init__(self):
22-
self.weights = None
22+
self.theta = None
2323

2424
def fit(self, X, y):
2525
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
26-
self.weights = np.linalg.pinv(X_bias.T @ X_bias) @ X_bias.T @ y
26+
self.theta = np.linalg.pinv(X_bias.T @ X_bias) @ X_bias.T @ y
2727

2828
def predict(self, X):
2929
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
30-
return X_bias @ self.weights
30+
return X_bias @ self.theta
3131

3232
class RidgeRegression:
33-
def __init__(self, theta=1.0):
34-
self.theta = theta
35-
self.weights = None
33+
def __init__(self, lam=1.0):
34+
self.lam = lam
35+
self.theta = None
3636

3737
def fit(self, X, y):
3838
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
3939
n = X_bias.shape[1]
4040
I = np.eye(n)
4141
I[0, 0] = 0
42-
self.weights = np.linalg.pinv(X_bias.T @ X_bias + self.theta * I) @ X_bias.T @ y
42+
self.theta = np.linalg.pinv(X_bias.T @ X_bias + self.lam * I) @ X_bias.T @ y
4343

4444
def predict(self, X):
4545
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
46-
return X_bias @ self.weights
46+
return X_bias @ self.theta
4747

4848
class LassoRegression:
49-
def __init__(self, theta=1.0, max_iter=1000, tol=1e-4):
50-
self.theta = theta
49+
def __init__(self, lam=1.0, max_iter=1000, tol=1e-4):
50+
self.lam = lam
5151
self.max_iter = max_iter
5252
self.tol = tol
53-
self.weights = None
53+
self.theta = None
5454

5555
def fit(self, X, y):
5656
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
5757
n_samples, n_features = X_bias.shape
58-
self.weights = np.zeros(n_features)
58+
self.theta = np.zeros(n_features)
5959

6060
for _ in range(self.max_iter):
61-
weights_old = self.weights.copy()
61+
theta_old = self.theta.copy()
6262
for j in range(n_features):
63-
tmp = X_bias @ self.weights - X_bias[:, j] * self.weights[j]
63+
tmp = X_bias @ self.theta - X_bias[:, j] * self.theta[j]
6464
rho = np.dot(X_bias[:, j], y - tmp)
6565
if j == 0:
66-
self.weights[j] = rho / np.sum(X_bias[:, j] ** 2)
66+
self.theta[j] = rho / np.sum(X_bias[:, j] ** 2)
6767
else:
68-
if rho < -self.theta / 2:
69-
self.weights[j] = (rho + self.theta / 2) / np.sum(X_bias[:, j] ** 2)
70-
elif rho > self.theta / 2:
71-
self.weights[j] = (rho - self.theta / 2) / np.sum(X_bias[:, j] ** 2)
68+
if rho < -self.lam / 2:
69+
self.theta[j] = (rho + self.lam / 2) / np.sum(X_bias[:, j] ** 2)
70+
elif rho > self.lam / 2:
71+
self.theta[j] = (rho - self.lam / 2) / np.sum(X_bias[:, j] ** 2)
7272
else:
73-
self.weights[j] = 0
74-
if np.linalg.norm(self.weights - weights_old, ord=1) < self.tol:
73+
self.theta[j] = 0
74+
if np.linalg.norm(self.theta - theta_old, ord=1) < self.tol:
7575
break
7676

7777
def predict(self, X):
7878
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
79-
return X_bias @ self.weights
79+
return X_bias @ self.theta
8080

8181
class KernelRidgeRegression:
82-
def __init__(self, theta=1.0, gamma=0.1):
83-
self.theta = theta
82+
def __init__(self, lam=1.0, gamma=0.1):
83+
self.lam = lam
8484
self.gamma = gamma
8585
self.X_train = None
86-
self.theta_vec = None
86+
self.lam_vec = None
8787

8888
def _rbf_kernel(self, X1, X2):
8989
dists = np.sum((X1[:, np.newaxis] - X2[np.newaxis, :]) ** 2, axis=2)
@@ -93,11 +93,11 @@ def fit(self, X, y):
9393
self.X_train = X
9494
K = self._rbf_kernel(X, X)
9595
n = K.shape[0]
96-
self.theta_vec = np.linalg.pinv(K + self.theta * np.eye(n)) @ y
96+
self.lam_vec = np.linalg.pinv(K + self.lam * np.eye(n)) @ y
9797

9898
def predict(self, X):
9999
K = self._rbf_kernel(X, self.X_train)
100-
return K @ self.theta_vec
100+
return K @ self.lam_vec
101101

102102
if __name__ == "__main__":
103103
np.random.seed(42)
@@ -106,9 +106,9 @@ def predict(self, X):
106106

107107
models = {
108108
"linear": LinearRegression(),
109-
"ridge": RidgeRegression(theta=1.0),
110-
"lasso": LassoRegression(theta=0.1),
111-
"kernel_ridge": KernelRidgeRegression(theta=1.0, gamma=5.0)
109+
"ridge": RidgeRegression(lam=1.0),
110+
"lasso": LassoRegression(lam=0.1),
111+
"kernel_ridge": KernelRidgeRegression(lam=1.0, gamma=5.0)
112112
}
113113

114114
for name, model in models.items():

0 commit comments

Comments
 (0)