121 lines
4.0 KiB
Python
121 lines
4.0 KiB
Python
import numpy as np
|
|
import csv
|
|
import matplotlib.pyplot as plt
|
|
|
|
def mse(y_true, y_pred):
|
|
return np.mean((y_true - y_pred) ** 2)
|
|
|
|
def r2_score(y_true, y_pred):
|
|
ss_total = np.sum((y_true - np.mean(y_true)) ** 2)
|
|
ss_res = np.sum((y_true - y_pred) ** 2)
|
|
return 1 - ss_res / ss_total
|
|
|
|
def save_csv(filename, X, y_true, y_pred):
|
|
with open(filename, mode='w', newline='') as file:
|
|
writer = csv.writer(file)
|
|
writer.writerow(["X", "True Y", "Predicted Y"])
|
|
for x, y, y_hat in zip(X, y_true, y_pred):
|
|
writer.writerow([x[0], y, y_hat])
|
|
|
|
class LinearRegression:
|
|
def __init__(self):
|
|
self.weights = None
|
|
|
|
def fit(self, X, y):
|
|
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
|
|
self.weights = np.linalg.pinv(X_bias.T @ X_bias) @ X_bias.T @ y
|
|
|
|
def predict(self, X):
|
|
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
|
|
return X_bias @ self.weights
|
|
|
|
class RidgeRegression:
|
|
def __init__(self, theta=1.0):
|
|
self.theta = theta
|
|
self.weights = None
|
|
|
|
def fit(self, X, y):
|
|
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
|
|
n = X_bias.shape[1]
|
|
I = np.eye(n)
|
|
I[0, 0] = 0
|
|
self.weights = np.linalg.pinv(X_bias.T @ X_bias + self.theta * I) @ X_bias.T @ y
|
|
|
|
def predict(self, X):
|
|
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
|
|
return X_bias @ self.weights
|
|
|
|
class LassoRegression:
|
|
def __init__(self, theta=1.0, max_iter=1000, tol=1e-4):
|
|
self.theta = theta
|
|
self.max_iter = max_iter
|
|
self.tol = tol
|
|
self.weights = None
|
|
|
|
def fit(self, X, y):
|
|
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
|
|
n_samples, n_features = X_bias.shape
|
|
self.weights = np.zeros(n_features)
|
|
|
|
for _ in range(self.max_iter):
|
|
weights_old = self.weights.copy()
|
|
for j in range(n_features):
|
|
tmp = X_bias @ self.weights - X_bias[:, j] * self.weights[j]
|
|
rho = np.dot(X_bias[:, j], y - tmp)
|
|
if j == 0:
|
|
self.weights[j] = rho / np.sum(X_bias[:, j] ** 2)
|
|
else:
|
|
if rho < -self.theta / 2:
|
|
self.weights[j] = (rho + self.theta / 2) / np.sum(X_bias[:, j] ** 2)
|
|
elif rho > self.theta / 2:
|
|
self.weights[j] = (rho - self.theta / 2) / np.sum(X_bias[:, j] ** 2)
|
|
else:
|
|
self.weights[j] = 0
|
|
if np.linalg.norm(self.weights - weights_old, ord=1) < self.tol:
|
|
break
|
|
|
|
def predict(self, X):
|
|
X_bias = np.c_[np.ones((X.shape[0], 1)), X]
|
|
return X_bias @ self.weights
|
|
|
|
class KernelRidgeRegression:
|
|
def __init__(self, theta=1.0, gamma=0.1):
|
|
self.theta = theta
|
|
self.gamma = gamma
|
|
self.X_train = None
|
|
self.theta_vec = None
|
|
|
|
def _rbf_kernel(self, X1, X2):
|
|
dists = np.sum((X1[:, np.newaxis] - X2[np.newaxis, :]) ** 2, axis=2)
|
|
return np.exp(-self.gamma * dists)
|
|
|
|
def fit(self, X, y):
|
|
self.X_train = X
|
|
K = self._rbf_kernel(X, X)
|
|
n = K.shape[0]
|
|
self.theta_vec = np.linalg.pinv(K + self.theta * np.eye(n)) @ y
|
|
|
|
def predict(self, X):
|
|
K = self._rbf_kernel(X, self.X_train)
|
|
return K @ self.theta_vec
|
|
|
|
if __name__ == "__main__":
|
|
np.random.seed(42)
|
|
X = 2 * np.random.rand(100, 1)
|
|
y = 4 + 3 * X[:, 0] + np.random.randn(100) * 0.5
|
|
|
|
models = {
|
|
"linear": LinearRegression(),
|
|
"ridge": RidgeRegression(theta=1.0),
|
|
"lasso": LassoRegression(theta=0.1),
|
|
"kernel_ridge": KernelRidgeRegression(theta=1.0, gamma=5.0)
|
|
}
|
|
|
|
for name, model in models.items():
|
|
model.fit(X, y)
|
|
y_pred = model.predict(X)
|
|
mse_val = mse(y, y_pred)
|
|
r2_val = r2_score(y, y_pred)
|
|
print(f"{name} -> MSE: {mse_val:.4f}, R2: {r2_val:.4f}")
|
|
save_csv(f"predictions_{name}.csv", X, y, y_pred)
|