吴恩达机器学习课程 10 大编程练习精解从理论公式到 5 个 NumPy 实现陷阱在机器学习的入门阶段理论与实践的结合往往是最具挑战性的部分。吴恩达教授的机器学习课程以其系统性和实践性著称但许多学习者在将数学推导转化为代码时常常陷入一些看似简单却影响深远的陷阱。本文将深入剖析课程中 ex1-ex8 编程练习的 5 个最常见 NumPy/Python 实现错误并提供从理论到代码的完整思维路径。1. 向量化思维的缺失线性回归中的效率陷阱线性回归是机器学习入门的第一个编程练习也是向量化思维的最佳训练场。许多学习者习惯用 for 循环实现代价函数和梯度下降这不仅效率低下还错失了理解线性代数本质的机会。代价函数的数学表达J(θ) 1/(2m) * Σ(hθ(x^(i)) - y^(i))^2低效实现常见错误def compute_cost(X, y, theta): m len(y) total 0 for i in range(m): total (np.dot(X[i], theta) - y[i]) ** 2 return total / (2 * m)高效向量化实现def compute_cost(X, y, theta): m len(y) error X theta - y # 向量化计算所有预测误差 return (error.T error) / (2 * m) # 向量化平方和关键差异向量化版本利用矩阵运算同时处理所有样本执行速度可提升 100 倍以上在 10,000 个样本的测试中更符合数学公式的原始表达形式提示在 Python 中运算符执行矩阵乘法比np.dot()更直观且支持更高维数组2. 维度不匹配逻辑回归中的广播机制误用逻辑回归练习中sigmoid 函数的实现看似简单但维度处理不当会导致难以调试的错误。特别是在多特征情况下参数 θ 和特征矩阵 X 的维度对齐至关重要。常见错误场景# 错误示例未考虑θ是列向量 def sigmoid(z): return 1 / (1 np.exp(-z)) def predict(X, theta): return sigmoid(X * theta) # 错误使用*而非矩阵乘法正确实现def sigmoid(z): return 1 / (1 np.exp(-z)) def predict(X, theta): return sigmoid(X theta) # 使用矩阵乘法确保维度对齐维度检查技巧print(fX shape: {X.shape}) # 应为 (m, n1) print(ftheta shape: {theta.shape}) # 应为 (n1, 1) print(fy shape: {y.shape}) # 应为 (m, 1)常见错误模式对比表错误类型典型表现修正方法逐元素乘法使用*而非检查矩阵乘法运算符维度转置错误未处理 θ 的行列方向明确使用theta.reshape(-1,1)广播机制滥用自动扩展导致计算错误显式指定维度keepdimsTrue3. 反向传播中的梯度验证神经网络调试的关键在神经网络练习中反向传播算法的正确实现是最大挑战。即使代码能运行微小的实现错误也可能导致模型无法收敛。梯度检验Gradient Checking是验证实现正确性的金标准。梯度检验实现步骤实现数值梯度计算def compute_numerical_gradient(J, theta, epsilon1e-4): num_grad np.zeros_like(theta) perturb np.zeros_like(theta) for i in range(len(theta)): perturb[i] epsilon loss1 J(theta - perturb) loss2 J(theta perturb) num_grad[i] (loss2 - loss1) / (2 * epsilon) perturb[i] 0 return num_grad对比分析梯度# 计算两种梯度 analytic_grad backprop(theta) # 你的反向传播实现 numerical_grad compute_numerical_gradient(cost_function, theta) # 计算相对差异 diff np.linalg.norm(analytic_grad - numerical_grad) / \ np.linalg.norm(analytic_grad numerical_grad) print(f梯度差异: {diff} (应1e-7))注意梯度检验仅用于调试阶段训练时必须关闭否则会极度降低性能常见反向传播错误模式未考虑正则化项的导数各层参数矩阵维度转置错误激活函数导数计算错误如 sigmoid 的导数应为g(z)*(1-g(z))累加梯度时未正确初始化4. 正则化陷阱偏差-方差权衡的实现细节正则化是控制模型复杂度的关键手段但在实现中常出现两种极端要么完全忽略正则化要么过度正则化导致模型欠拟合。正确实现需要理解正则化对代价函数和梯度的影响差异。线性回归正则化的数学表达J(θ) 1/(2m) [Σ(hθ(x^(i))-y^(i))^2 λΣθ_j^2] (j从1开始) ∂J/∂θ_0 (1/m) Σ(hθ(x^(i))-y^(i))x_j^(i) (对于j0) ∂J/∂θ_j (1/m) [Σ(hθ(x^(i))-y^(i))x_j^(i) λθ_j] (对于j≥1)正则化实现的典型错误# 错误对所有θ包括θ_0应用正则化 def compute_cost_reg(X, y, theta, lambda_): m len(y) error X theta - y reg (lambda_ / (2 * m)) * np.sum(theta ** 2) # 错误包含θ_0 return (error.T error) / (2 * m) reg正确实现def compute_cost_reg(X, y, theta, lambda_): m len(y) error X theta - y reg (lambda_ / (2 * m)) * np.sum(theta[1:]**2) # 排除θ_0 return (error.T error) / (2 * m) reg def compute_grad_reg(X, y, theta, lambda_): m len(y) grad np.zeros_like(theta) error X theta - y grad[0] X[:, 0].T error / m # θ_0的特殊处理 grad[1:] (X[:, 1:].T error) / m (lambda_ / m) * theta[1:] return grad正则化系数λ的选择策略λ值范围模型表现解决方案太小0.01高方差过拟合增大λ尝试0.1,1,10适中良好泛化通过交叉验证确认太大100高偏差欠拟合减小λ增加模型复杂度5. 高级优化算法的参数处理陷阱当使用scipy.optimize.minimize等高级优化算法时参数形状的要求常被忽视。这些优化器通常要求参数是一维数组而神经网络参数需要保持矩阵结构。参数转换的典型问题# 错误直接使用矩阵参数 res minimize(cost_function, theta_matrix, ...)正确的参数序列化/反序列化def flatten_params(theta_list): return np.concatenate([t.flatten() for t in theta_list]) def reshape_params(flat_params, shapes): params [] pos 0 for shape in shapes: size np.prod(shape) params.append(flat_params[pos:possize].reshape(shape)) pos size return params # 使用示例 initial_theta [np.random.rand(5,4), np.random.rand(3,6)] flat_theta flatten_params(initial_theta) shapes [t.shape for t in initial_theta] def cost_func(flat_theta): theta_list reshape_params(flat_theta, shapes) # 使用theta_list计算代价和梯度 return cost, flatten_params(grad_list) res minimize(cost_func, flat_theta, jacTrue, methodL-BFGS-B)优化算法选择对比表算法优点缺点适用场景L-BFGS-B内存高效收敛快需要精确梯度中小规模参数CG无需存储Hessian矩阵收敛较慢大规模问题TNC处理边界约束可能陷入局部最优带约束问题Adam自适应学习率需要调参深度学习6. 从数学推导到代码的思维导图理解理论公式与代码实现的映射关系是掌握机器学习的核心能力。以下以反向传播为例展示这种思维转换数学公式 → Python实现的关键对应关系前向传播公式a^(1) x z^(2) Θ^(1)a^(1) a^(2) g(z^(2)) ...代码实现a1 X # 添加偏置单元 z2 a1 Theta1.T a2 sigmoid(z2) a2 np.hstack([np.ones((a2.shape[0], 1)), a2])误差计算δ^(L) a^(L) - y δ^(l) (Θ^(l))^T δ^(l1) .* g(z^(l))代码实现delta3 a3 - y_matrix delta2 delta3 Theta2[:, 1:] * sigmoid_gradient(z2)梯度累积Δ^(l) : Δ^(l) δ^(l1)(a^(l))^T D^(l) : (1/m)Δ^(l) λΘ^(l) (j≠0)代码实现Theta1_grad delta2.T a1 / m Theta1_grad[:, 1:] (lambda_ / m) * Theta1[:, 1:]7. 数据预处理中的隐藏陷阱正确的数据预处理对模型性能有决定性影响但实践中常被忽视。以下是三个关键注意事项特征缩放的两种方法对比方法公式适用场景NumPy实现标准化(x - μ)/σ特征大致正态分布(X - np.mean(X, axis0)) / np.std(X, axis0)最大最小缩放(x - min)/(max - min)特征边界明确(X - np.min(X, axis0)) / (np.max(X, axis0) - np.min(X, axis0))分类数据编码的注意事项# 错误直接给类别赋值数字 categories [红, 绿, 蓝] X[color_code] X[color].apply(lambda x: categories.index(x)) # 正确使用独热编码 from sklearn.preprocessing import OneHotEncoder encoder OneHotEncoder(sparseFalse) color_encoded encoder.fit_transform(X[[color]])训练/测试集分割的时间序列问题# 错误随机分割时间序列数据 from sklearn.model_selection import train_test_split X_train, X_test train_test_split(X, test_size0.2) # 破坏时间相关性 # 正确按时间顺序分割 split_idx int(len(X) * 0.8) X_train, X_test X[:split_idx], X[split_idx:]8. 模型评估中的维度诅咒在练习5偏差-方差分析和练习7PCA中正确评估模型性能需要理解维度的影响。以下是关键实践要点学习曲线的正确绘制方法def plot_learning_curve(X, y, Xval, yval, lambda_0): m len(y) error_train np.zeros(m) error_val np.zeros(m) for i in range(1, m1): theta train_model(X[:i], y[:i], lambda_) error_train[i-1] compute_cost(X[:i], y[:i], theta) error_val[i-1] compute_cost(Xval, yval, theta) plt.plot(range(1,m1), error_train, labelTrain) plt.plot(range(1,m1), error_val, labelCross Validation) plt.xlabel(Number of training examples) plt.ylabel(Error)PCA实现的关键步骤def pca(X, k): # 特征标准化 X_norm (X - np.mean(X, axis0)) / np.std(X, axis0) # 计算协方差矩阵 sigma X_norm.T X_norm / len(X) # 奇异值分解 U, S, V np.linalg.svd(sigma) # 选择前k个主成分 U_reduce U[:, :k] # 投影到低维空间 Z X_norm U_reduce return Z, U_reduce, S维度选择的标准# 计算保留的方差比例 def explained_variance(S, k): return np.sum(S[:k]) / np.sum(S) # 选择最小k使得保留99%方差 for k in range(1, len(S)1): if explained_variance(S, k) 0.99: print(f推荐维度: {k} (解释方差: {explained_variance(S, k):.2%})) break9. 推荐系统实现中的冷启动问题在练习8的推荐系统部分协同过滤算法面临新用户或新物品的评分预测难题。以下是两种解决方案的对比实现均值归一化处理def normalize_ratings(Y, R): Y: 评分矩阵 (m x n) R: 评分指示矩阵 (m x n) m, n Y.shape Ymean np.sum(Y, axis1) / np.sum(R, axis1) Ynorm Y - Ymean.reshape(-1, 1) * R # 仅对已有评分归一化 return Ynorm, Ymean # 预测时恢复原始评分 def predict_rating(X, Theta, Ymean, user_idx, movie_idx): return X[movie_idx] Theta[user_idx].T Ymean[user_idx]混合模型方法def hybrid_recommendation(user_features, item_features, content_features, alpha0.5): # 协同过滤部分 cf_score user_features item_features.T # 基于内容部分 content_sim cosine_similarity(item_features, content_features) # 混合预测 return alpha * cf_score (1 - alpha) * content_sim10. 异常检测中的多变量高斯分布实现练习8的异常检测部分单变量与多变量高斯模型的实现差异常被混淆。以下是关键区别单变量高斯分布实现def estimate_gaussian(X): mu np.mean(X, axis0) sigma2 np.var(X, axis0, ddof0) # 使用总体方差 return mu, sigma2 def multivariate_gaussian(X, mu, sigma2): p np.prod(1 / np.sqrt(2 * np.pi * sigma2)) * \ np.exp(-0.5 * np.sum((X - mu)**2 / sigma2, axis1)) return p多变量高斯分布实现def estimate_multivariate_gaussian(X): mu np.mean(X, axis0) sigma (X - mu).T (X - mu) / len(X) return mu, sigma def multivariate_gaussian(X, mu, sigma): n len(mu) X X - mu p (2 * np.pi) ** (-n / 2) * np.linalg.det(sigma) ** (-0.5) * \ np.exp(-0.5 * np.sum(X np.linalg.pinv(sigma) * X, axis1)) return p模型选择标准标准单变量模型多变量模型计算复杂度O(n)O(n^3) (因矩阵求逆)特征关系忽略特征间相关性自动捕捉相关性数据要求适用于小样本需要 m 10n 避免奇异矩阵实现难度简单需处理数值稳定性问题在完成所有练习后我习惯将每个算法的核心实现封装成可复用的类这不仅加深了对算法整体架构的理解也为后续项目积累了宝贵的基础代码库。例如一个标准的线性回归类应该包含 fit、predict、score 等方法并支持不同的优化算法选择。这种工程化的思维模式是从课程练习到实际应用的重要跨越。
吴恩达机器学习课程 10 大编程练习精解:从理论公式到 5 个 NumPy 实现陷阱
发布时间:2026/7/6 12:31:29
吴恩达机器学习课程 10 大编程练习精解从理论公式到 5 个 NumPy 实现陷阱在机器学习的入门阶段理论与实践的结合往往是最具挑战性的部分。吴恩达教授的机器学习课程以其系统性和实践性著称但许多学习者在将数学推导转化为代码时常常陷入一些看似简单却影响深远的陷阱。本文将深入剖析课程中 ex1-ex8 编程练习的 5 个最常见 NumPy/Python 实现错误并提供从理论到代码的完整思维路径。1. 向量化思维的缺失线性回归中的效率陷阱线性回归是机器学习入门的第一个编程练习也是向量化思维的最佳训练场。许多学习者习惯用 for 循环实现代价函数和梯度下降这不仅效率低下还错失了理解线性代数本质的机会。代价函数的数学表达J(θ) 1/(2m) * Σ(hθ(x^(i)) - y^(i))^2低效实现常见错误def compute_cost(X, y, theta): m len(y) total 0 for i in range(m): total (np.dot(X[i], theta) - y[i]) ** 2 return total / (2 * m)高效向量化实现def compute_cost(X, y, theta): m len(y) error X theta - y # 向量化计算所有预测误差 return (error.T error) / (2 * m) # 向量化平方和关键差异向量化版本利用矩阵运算同时处理所有样本执行速度可提升 100 倍以上在 10,000 个样本的测试中更符合数学公式的原始表达形式提示在 Python 中运算符执行矩阵乘法比np.dot()更直观且支持更高维数组2. 维度不匹配逻辑回归中的广播机制误用逻辑回归练习中sigmoid 函数的实现看似简单但维度处理不当会导致难以调试的错误。特别是在多特征情况下参数 θ 和特征矩阵 X 的维度对齐至关重要。常见错误场景# 错误示例未考虑θ是列向量 def sigmoid(z): return 1 / (1 np.exp(-z)) def predict(X, theta): return sigmoid(X * theta) # 错误使用*而非矩阵乘法正确实现def sigmoid(z): return 1 / (1 np.exp(-z)) def predict(X, theta): return sigmoid(X theta) # 使用矩阵乘法确保维度对齐维度检查技巧print(fX shape: {X.shape}) # 应为 (m, n1) print(ftheta shape: {theta.shape}) # 应为 (n1, 1) print(fy shape: {y.shape}) # 应为 (m, 1)常见错误模式对比表错误类型典型表现修正方法逐元素乘法使用*而非检查矩阵乘法运算符维度转置错误未处理 θ 的行列方向明确使用theta.reshape(-1,1)广播机制滥用自动扩展导致计算错误显式指定维度keepdimsTrue3. 反向传播中的梯度验证神经网络调试的关键在神经网络练习中反向传播算法的正确实现是最大挑战。即使代码能运行微小的实现错误也可能导致模型无法收敛。梯度检验Gradient Checking是验证实现正确性的金标准。梯度检验实现步骤实现数值梯度计算def compute_numerical_gradient(J, theta, epsilon1e-4): num_grad np.zeros_like(theta) perturb np.zeros_like(theta) for i in range(len(theta)): perturb[i] epsilon loss1 J(theta - perturb) loss2 J(theta perturb) num_grad[i] (loss2 - loss1) / (2 * epsilon) perturb[i] 0 return num_grad对比分析梯度# 计算两种梯度 analytic_grad backprop(theta) # 你的反向传播实现 numerical_grad compute_numerical_gradient(cost_function, theta) # 计算相对差异 diff np.linalg.norm(analytic_grad - numerical_grad) / \ np.linalg.norm(analytic_grad numerical_grad) print(f梯度差异: {diff} (应1e-7))注意梯度检验仅用于调试阶段训练时必须关闭否则会极度降低性能常见反向传播错误模式未考虑正则化项的导数各层参数矩阵维度转置错误激活函数导数计算错误如 sigmoid 的导数应为g(z)*(1-g(z))累加梯度时未正确初始化4. 正则化陷阱偏差-方差权衡的实现细节正则化是控制模型复杂度的关键手段但在实现中常出现两种极端要么完全忽略正则化要么过度正则化导致模型欠拟合。正确实现需要理解正则化对代价函数和梯度的影响差异。线性回归正则化的数学表达J(θ) 1/(2m) [Σ(hθ(x^(i))-y^(i))^2 λΣθ_j^2] (j从1开始) ∂J/∂θ_0 (1/m) Σ(hθ(x^(i))-y^(i))x_j^(i) (对于j0) ∂J/∂θ_j (1/m) [Σ(hθ(x^(i))-y^(i))x_j^(i) λθ_j] (对于j≥1)正则化实现的典型错误# 错误对所有θ包括θ_0应用正则化 def compute_cost_reg(X, y, theta, lambda_): m len(y) error X theta - y reg (lambda_ / (2 * m)) * np.sum(theta ** 2) # 错误包含θ_0 return (error.T error) / (2 * m) reg正确实现def compute_cost_reg(X, y, theta, lambda_): m len(y) error X theta - y reg (lambda_ / (2 * m)) * np.sum(theta[1:]**2) # 排除θ_0 return (error.T error) / (2 * m) reg def compute_grad_reg(X, y, theta, lambda_): m len(y) grad np.zeros_like(theta) error X theta - y grad[0] X[:, 0].T error / m # θ_0的特殊处理 grad[1:] (X[:, 1:].T error) / m (lambda_ / m) * theta[1:] return grad正则化系数λ的选择策略λ值范围模型表现解决方案太小0.01高方差过拟合增大λ尝试0.1,1,10适中良好泛化通过交叉验证确认太大100高偏差欠拟合减小λ增加模型复杂度5. 高级优化算法的参数处理陷阱当使用scipy.optimize.minimize等高级优化算法时参数形状的要求常被忽视。这些优化器通常要求参数是一维数组而神经网络参数需要保持矩阵结构。参数转换的典型问题# 错误直接使用矩阵参数 res minimize(cost_function, theta_matrix, ...)正确的参数序列化/反序列化def flatten_params(theta_list): return np.concatenate([t.flatten() for t in theta_list]) def reshape_params(flat_params, shapes): params [] pos 0 for shape in shapes: size np.prod(shape) params.append(flat_params[pos:possize].reshape(shape)) pos size return params # 使用示例 initial_theta [np.random.rand(5,4), np.random.rand(3,6)] flat_theta flatten_params(initial_theta) shapes [t.shape for t in initial_theta] def cost_func(flat_theta): theta_list reshape_params(flat_theta, shapes) # 使用theta_list计算代价和梯度 return cost, flatten_params(grad_list) res minimize(cost_func, flat_theta, jacTrue, methodL-BFGS-B)优化算法选择对比表算法优点缺点适用场景L-BFGS-B内存高效收敛快需要精确梯度中小规模参数CG无需存储Hessian矩阵收敛较慢大规模问题TNC处理边界约束可能陷入局部最优带约束问题Adam自适应学习率需要调参深度学习6. 从数学推导到代码的思维导图理解理论公式与代码实现的映射关系是掌握机器学习的核心能力。以下以反向传播为例展示这种思维转换数学公式 → Python实现的关键对应关系前向传播公式a^(1) x z^(2) Θ^(1)a^(1) a^(2) g(z^(2)) ...代码实现a1 X # 添加偏置单元 z2 a1 Theta1.T a2 sigmoid(z2) a2 np.hstack([np.ones((a2.shape[0], 1)), a2])误差计算δ^(L) a^(L) - y δ^(l) (Θ^(l))^T δ^(l1) .* g(z^(l))代码实现delta3 a3 - y_matrix delta2 delta3 Theta2[:, 1:] * sigmoid_gradient(z2)梯度累积Δ^(l) : Δ^(l) δ^(l1)(a^(l))^T D^(l) : (1/m)Δ^(l) λΘ^(l) (j≠0)代码实现Theta1_grad delta2.T a1 / m Theta1_grad[:, 1:] (lambda_ / m) * Theta1[:, 1:]7. 数据预处理中的隐藏陷阱正确的数据预处理对模型性能有决定性影响但实践中常被忽视。以下是三个关键注意事项特征缩放的两种方法对比方法公式适用场景NumPy实现标准化(x - μ)/σ特征大致正态分布(X - np.mean(X, axis0)) / np.std(X, axis0)最大最小缩放(x - min)/(max - min)特征边界明确(X - np.min(X, axis0)) / (np.max(X, axis0) - np.min(X, axis0))分类数据编码的注意事项# 错误直接给类别赋值数字 categories [红, 绿, 蓝] X[color_code] X[color].apply(lambda x: categories.index(x)) # 正确使用独热编码 from sklearn.preprocessing import OneHotEncoder encoder OneHotEncoder(sparseFalse) color_encoded encoder.fit_transform(X[[color]])训练/测试集分割的时间序列问题# 错误随机分割时间序列数据 from sklearn.model_selection import train_test_split X_train, X_test train_test_split(X, test_size0.2) # 破坏时间相关性 # 正确按时间顺序分割 split_idx int(len(X) * 0.8) X_train, X_test X[:split_idx], X[split_idx:]8. 模型评估中的维度诅咒在练习5偏差-方差分析和练习7PCA中正确评估模型性能需要理解维度的影响。以下是关键实践要点学习曲线的正确绘制方法def plot_learning_curve(X, y, Xval, yval, lambda_0): m len(y) error_train np.zeros(m) error_val np.zeros(m) for i in range(1, m1): theta train_model(X[:i], y[:i], lambda_) error_train[i-1] compute_cost(X[:i], y[:i], theta) error_val[i-1] compute_cost(Xval, yval, theta) plt.plot(range(1,m1), error_train, labelTrain) plt.plot(range(1,m1), error_val, labelCross Validation) plt.xlabel(Number of training examples) plt.ylabel(Error)PCA实现的关键步骤def pca(X, k): # 特征标准化 X_norm (X - np.mean(X, axis0)) / np.std(X, axis0) # 计算协方差矩阵 sigma X_norm.T X_norm / len(X) # 奇异值分解 U, S, V np.linalg.svd(sigma) # 选择前k个主成分 U_reduce U[:, :k] # 投影到低维空间 Z X_norm U_reduce return Z, U_reduce, S维度选择的标准# 计算保留的方差比例 def explained_variance(S, k): return np.sum(S[:k]) / np.sum(S) # 选择最小k使得保留99%方差 for k in range(1, len(S)1): if explained_variance(S, k) 0.99: print(f推荐维度: {k} (解释方差: {explained_variance(S, k):.2%})) break9. 推荐系统实现中的冷启动问题在练习8的推荐系统部分协同过滤算法面临新用户或新物品的评分预测难题。以下是两种解决方案的对比实现均值归一化处理def normalize_ratings(Y, R): Y: 评分矩阵 (m x n) R: 评分指示矩阵 (m x n) m, n Y.shape Ymean np.sum(Y, axis1) / np.sum(R, axis1) Ynorm Y - Ymean.reshape(-1, 1) * R # 仅对已有评分归一化 return Ynorm, Ymean # 预测时恢复原始评分 def predict_rating(X, Theta, Ymean, user_idx, movie_idx): return X[movie_idx] Theta[user_idx].T Ymean[user_idx]混合模型方法def hybrid_recommendation(user_features, item_features, content_features, alpha0.5): # 协同过滤部分 cf_score user_features item_features.T # 基于内容部分 content_sim cosine_similarity(item_features, content_features) # 混合预测 return alpha * cf_score (1 - alpha) * content_sim10. 异常检测中的多变量高斯分布实现练习8的异常检测部分单变量与多变量高斯模型的实现差异常被混淆。以下是关键区别单变量高斯分布实现def estimate_gaussian(X): mu np.mean(X, axis0) sigma2 np.var(X, axis0, ddof0) # 使用总体方差 return mu, sigma2 def multivariate_gaussian(X, mu, sigma2): p np.prod(1 / np.sqrt(2 * np.pi * sigma2)) * \ np.exp(-0.5 * np.sum((X - mu)**2 / sigma2, axis1)) return p多变量高斯分布实现def estimate_multivariate_gaussian(X): mu np.mean(X, axis0) sigma (X - mu).T (X - mu) / len(X) return mu, sigma def multivariate_gaussian(X, mu, sigma): n len(mu) X X - mu p (2 * np.pi) ** (-n / 2) * np.linalg.det(sigma) ** (-0.5) * \ np.exp(-0.5 * np.sum(X np.linalg.pinv(sigma) * X, axis1)) return p模型选择标准标准单变量模型多变量模型计算复杂度O(n)O(n^3) (因矩阵求逆)特征关系忽略特征间相关性自动捕捉相关性数据要求适用于小样本需要 m 10n 避免奇异矩阵实现难度简单需处理数值稳定性问题在完成所有练习后我习惯将每个算法的核心实现封装成可复用的类这不仅加深了对算法整体架构的理解也为后续项目积累了宝贵的基础代码库。例如一个标准的线性回归类应该包含 fit、predict、score 等方法并支持不同的优化算法选择。这种工程化的思维模式是从课程练习到实际应用的重要跨越。