在R中实现线性回归(Linear Regression)时遇到NaN值问题求助
排查并解决R线性回归梯度下降中的NaN问题
我帮你拆解下代码里的几个关键问题,尤其是导致NaN的核心原因:
1. 数据初始化与绘图的小bug
先看你开头的数据处理和绘图部分:
- 你先创建了空的
df <- data.frame(),接着用cbind生成数据再转成数据框,这一步其实可以直接一步到位,省点冗余操作;另外plot函数的参数用错了,正确的写法应该是把x轴(Population)放在前面,y轴(Profit)放在后面,比如plot(df$Population, df$Profit),或者用更简洁的公式风格plot(Profit ~ Population, data = df)。
修正后的初始化代码:
library(ggplot2) # 直接创建数据框,不用绕弯 df <- data.frame( Population = c(10000,20000,5000,5123,5345,5454,11000,23000,6000,6100,6300), Profit = c(5600,21000,1000,2000,2300,3000,7000,21400,3200,3250,3300) ) # 正确绘制散点图 plot(Profit ~ Population, data = df)
2. 导致NaN的核心元凶:没做特征缩放 + 学习率太大
这是最关键的问题!你的Population数值范围是500023000,`Profit`是100021400,数值量级都很大,但你设置的学习率alpha=0.001对于未缩放的特征来说实在太大了。梯度下降的时候,步长过大会导致损失函数值直接爆炸,最后溢出变成NaN。
解决方法很简单:先对特征做标准化(Z-score归一化),把特征缩放到均值为0、标准差为1的范围,之后再跑梯度下降就稳了。
3. 完整的修正版梯度下降代码
下面是调整后的完整代码,包含特征缩放、梯度下降的迭代过程,绝对不会出现NaN:
library(ggplot2) # 1. 一步创建数据框 df <- data.frame( Population = c(10000,20000,5000,5123,5345,5454,11000,23000,6000,6100,6300), Profit = c(5600,21000,1000,2000,2300,3000,7000,21400,3200,3250,3300) ) # 2. 特征标准化(这步一定要做!) # 先保存均值和标准差,后面要还原拟合结果用 pop_mean <- mean(df$Population) pop_sd <- sd(df$Population) df$Population_scaled <- (df$Population - pop_mean) / pop_sd # 3. 准备梯度下降的矩阵 X <- cbind(1, df$Population_scaled) # 加入截距项 Y <- df$Profit theta <- c(0, 0) # 初始化参数 m <- nrow(X) alpha <- 0.01 # 缩放后用这个学习率刚好 iterations <- 1500 cost_history <- numeric(iterations) # 记录每一轮的损失值,方便看收敛情况 # 4. 梯度下降迭代循环(你之前没写这部分哦) for (i in 1:iterations) { predictions <- X %*% theta error <- predictions - Y # 更新theta参数 theta <- theta - (alpha/m) * t(X) %*% error # 计算当前损失并保存 cost_history[i] <- sum(error^2)/(2*m) } # 查看最终的参数和损失变化 print(theta) plot(cost_history, type = "l", xlab = "迭代次数", ylab = "损失函数值") # 5. 用拟合结果画个图直观看看 df$Predicted_Profit <- X %*% theta ggplot(df, aes(x = Population, y = Profit)) + geom_point() + geom_line(aes(y = Predicted_Profit), color = "red", linewidth = 1) + labs(title = "人口 vs 利润(线性回归拟合)", x = "人口数量", y = "利润")
额外小提示
- 如果你实在不想做特征缩放,也可以试试把学习率调得极小(比如
alpha=1e-8),但这样梯度下降收敛会超级慢,远不如特征缩放高效。 - 你之前的代码只算了初始的损失值,没写梯度下降的迭代循环,这也是没法得到回归结果的原因之一哦。
内容的提问来源于stack exchange,提问作者Neeraj Sharma
相关产品推荐
相关产品推荐

