
线性回归是一种基本的预测模型,通过找到最佳的线性关系来拟合输入特征(features)与目标值(targets)之间的关系。其核心在于定义一个假设函数(hypothesis),一个成本函数(cost_function)来衡量模型预测的准确性,并通过梯度下降(gradientDescent)算法迭代地更新模型参数(params),以最小化成本函数。
一个典型的线性回归实现会包含以下关键组件:
以下是一个从零实现的线性回归类的基本结构:
import numpy as np
class LinearRegression:
def __init__(
self,
features: np.ndarray[np.float64],
targets: np.ndarray[np.float64],
) -> None:
# 在特征矩阵X前添加一列1,用于偏置项
self.features = np.concatenate((np.ones((features.shape[0], 1)), features), axis=1)
self.targets = targets
# 随机初始化参数
self.params = np.random.randn(features.shape[1] + 1)
self.num_samples = features.shape[0]
self.num_feats = features.shape[1]
self.costs = [] # 用于记录每次迭代的成本
def hypothesis(self) -> np.ndarray[np.float64]:
# 假设函数:X * theta
return np.dot(self.features, self.params)
def cost_function(self) -> np.float64:
# 均方误差成本函数 J(theta) = 1/(2m) * sum((h(x) - y)^2)
pred_vals = self.hypothesis()
return (1 / (2 * self.num_samples)) * np.dot((pred_vals - self.targets).T, pred_vals - self.targets)
def update(self, alpha: np.float64) -> None:
# 参数更新:theta = theta - alpha/m * (X.T @ (h(x) - y))
self.params = self.params - (alpha / self.num_samples) * (self.features.T @ (self.hypothesis() - self.targets))
def gradientDescent(self, alpha: np.float64, threshold: np.float64, max_iter: int) -> None:
converged = False
counter = 0
while not converged:
counter += 1
curr_cost = self.cost_function()
self.costs.append(curr_cost)
self.update(alpha) # 更新参数
new_cost = self.cost_function()
# 判断收敛条件:成本函数变化小于阈值或达到最大迭代次数
if abs(new_cost - curr_cost) < threshold:
converged = True
if counter > max_iter:
converged = True在上述线性回归实现中,当输入数据(features和targets)的数值范围过大时,梯度下降过程极易出现数值溢出(overflow)和无效值(invalid value)警告。
立即学习“Python免费学习笔记(深入)”;
例如,如果使用以下方式初始化和运行模型:
# 使用大范围的输入数据
regr = LinearRegression(features=np.linspace(0, 1000, 200, dtype=np.float64).reshape((20, 10)),
targets=np.linspace(0, 200, 20, dtype=np.float64))
regr.gradientDescent(0.1, 1e-3, 1e+3)
regr.cost_function()可能会遇到以下运行时警告:
RuntimeWarning: overflow encountered in scalar power RuntimeWarning: invalid value encountered in scalar subtract RuntimeWarning: overflow encountered in matmul
这些警告表明在计算过程中产生了超出float64数据类型表示范围的巨大数值(如inf或-inf),或者由这些无限值导致的无效计算结果(如inf - inf产生NaN)。
原因分析:
解决数值溢出问题的最有效方法是对输入数据进行缩放(Scaling)。通过将特征和目标值转换到一个较小的、标准化的范围,可以显著提高数值稳定性,并帮助梯度下降算法更有效地收敛。
常见的缩放方法包括:
对于本例中的问题,简单地将输入数据除以一个较大的常数,使其数值范围缩小,即可有效避免溢出。
修正后的代码示例:
# 将特征和目标值缩小1000倍
regr = LinearRegression(features=np.linspace(0, 1000, 200, dtype=np.float64).reshape((20, 10))/1000,
targets=np.linspace(0, 200, 20, dtype=np.float64)/1000)
regr.gradientDescent(0.1, 1e-3, 1e+3)
final_cost = regr.cost_function()
print(f"最终成本函数值: {final_cost}")
# 示例输出:最终成本函数值: 0.00474225348416323通过将 features 和 targets 都除以1000,它们的数值范围显著缩小,从而避免了在成本函数和梯度更新计算中出现中间结果溢出。模型现在能够正常运行,并收敛到一个合理的成本函数值。
在Python中从零实现线性回归等机器学习算法时,数值稳定性是一个不容忽视的关键问题。当输入数据数值范围过大时,计算过程中可能发生浮点数溢出,导致模型训练失败。通过对数据进行适当的缩放(如归一化或标准化),可以将数值保持在可管理的范围内,从而有效解决溢出问题,确保梯度下降算法的稳定运行和模型的正确收敛。理解并应用数据预处理技术是构建健壮机器学习模型的基石。
以上就是解决Python从零实现线性回归中的数值溢出问题的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号