import numpy as np
%matplotlib widget
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = ["sans-serif","SimHei"]
plt.rcParams['axes.unicode_minus'] = False
def sigmoid(z):
z = np.clip(z, -500, 500)
g = 1.0 / (1.0 + np.exp(-z))
return g
def compute_cost_logistic_reg(X, y, w, b, lambda_=1):
m, n = X.shape
cost = 0.0
for i in range(m):
z_i = np.dot(X[i], w) + b
f_wb_i = sigmoid(z_i)
cost += -y[i] * np.log(f_wb_i) - (1 - y[i]) * np.log(1 - f_wb_i)
cost /= m
reg_cost = (lambda_ / (2 * m)) * np.sum(w **2)
total_cost = cost + reg_cost
return total_cost
def compute_gradient_logistic_reg(X, y, w, b, lambda_):
m, n = X.shape
dj_dw = np.zeros((n,))
dj_db = 0.0
for i in range(m):
f_wb_i = sigmoid(np.dot(X[i], w) + b)
err_i = f_wb_i - y[i]
for j in range(n):
dj_dw[j] += err_i * X[i, j]
dj_db += err_i
dj_dw /= m
dj_db /= m
dj_dw += (lambda_ / m) * w
return dj_db, dj_dw
def gradient_descent(X, y, w_in, b_in, cost_function, gradient_function,
alpha, num_iters, lambda_):
J_history = []
w = w_in.copy()
b = b_in
for i in range(num_iters):
dj_db, dj_dw = gradient_function(X, y, w, b, lambda_)
w = w - alpha * dj_dw
b = b - alpha * dj_db
if i % 100 == 0:
J_history.append(cost_function(X, y, w, b, lambda_))
return w, b, J_history
def tune_regularization(X_train, y_train, X_cv, y_cv):
lambda_range = np.array([0.0, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, 10, 100,200,300,500,800,1000])
num_steps = len(lambda_range)
err_train = np.zeros(num_steps)
err_cv = np.zeros(num_steps)
n = X_train.shape[1]
initial_w = np.zeros(n)
initial_b = 0.0
alpha = 0.01
num_iters = 10000
best_w = None
best_b = None
best_lambda = None
min_cv_error = float('inf')
for i in range(num_steps):
lambda_ = lambda_range[i]
print(f"正在训练 lambda = {lambda_}")
w, b, _ = gradient_descent(X_train, y_train, initial_w, initial_b,
compute_cost_logistic_reg,
compute_gradient_logistic_reg,
alpha, num_iters, lambda_)
train_cost = compute_cost_logistic_reg(X_train, y_train, w, b, lambda_=0)
err_train[i] = train_cost
cv_cost = compute_cost_logistic_reg(X_cv, y_cv, w, b, lambda_=0)
err_cv[i] = cv_cost
if cv_cost < min_cv_error:
min_cv_error = cv_cost
best_w = w
best_b = b
best_lambda = lambda_
optimal_reg_idx = np.argmin(err_cv)
plt.figure(figsize=(10, 6))
plt.semilogx(lambda_range, err_train, label='训练损失')
plt.semilogx(lambda_range, err_cv, label='验证损失')
plt.xlabel('正则化参数 λ')
plt.ylabel('损失')
plt.title('不同正则化参数下的损失曲线')
plt.axvline(x=lambda_range[optimal_reg_idx], color='r', linestyle='--',
label=f'最优λ = {lambda_range[optimal_reg_idx]}')
plt.legend()
plt.grid(True)
plt.show()
print(f"最优正则化参数: λ = {best_lambda}")
print(f"最优参数对应的验证集损失: {min_cv_error:.4f}")
return best_w, best_b, best_lambda, err_train, err_cv
np.random.seed(42)
m = 500
n = 10
X = np.random.randn(m, n)
true_w = np.random.randn(n) * 0.5
true_b = np.random.randn() * 0.3
z = np.dot(X, true_w) + true_b
probabilities = sigmoid(z)
y = np.random.binomial(1, probabilities)
noise_features = np.random.randn(m, 5)
X = np.hstack([X, noise_features])
n = X.shape[1]
split_idx = int(m * 0.8)
X_train, X_cv = X[:split_idx], X[split_idx:]
y_train, y_cv = y[:split_idx], y[split_idx:]
mean = np.mean(X_train, axis=0)
std = np.std(X_train, axis=0)
std[std == 0] = 1
X_train = (X_train - mean) / std
X_cv = (X_cv - mean) / std
best_w, best_b, best_lambda, train_errors, cv_errors = tune_regularization(X_train, y_train, X_cv, y_cv)
def predict(X, w, b):
"""使用训练好的参数进行预测"""
m = X.shape[0]
y_pred = np.zeros(m)
for i in range(m):
z = np.dot(X[i], w) + b
f_wb = sigmoid(z)
y_pred[i] = 1 if f_wb >= 0.5 else 0
return y_pred
y_pred_train = predict(X_train, best_w, best_b)
y_pred_cv = predict(X_cv, best_w, best_b)
train_accuracy = np.mean(y_pred_train == y_train)
cv_accuracy = np.mean(y_pred_cv == y_cv)
print(f"训练集准确率: {train_accuracy:.4f}")
print(f"验证集准确率: {cv_accuracy:.4f}")