You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用R中lm()与bs()绘制样条遇行数不匹配错误及相关咨询

问题解决与答疑

错误原因分析

你遇到的'newdata' has 38 rows, but the variables found have 700 rows错误,根源有两个:

  1. 构建模型时直接用了data_clean$visits、data_clean$discount这种硬编码列引用,而非数据框内的变量名。这会让模型把这些向量当作全局变量,而非数据框的列,导致predict无法匹配newdata里的变量。
  2. 模型包含discount变量,但调用predict时的newdata只提供了visits,缺少discount的取值,模型无法完成预测。
    另外,bs()里同时设置df=3和knots=3存在冲突:df=3的样条默认只需要2个内部节点,手动设knots=3会导致自由度不匹配,建议只保留df参数。

疑问解答

1. 如何从样条模型生成可用于绘图的曲线?

按以下步骤操作:

  • 修正模型定义:使用变量名而非硬编码列引用,让模型正确关联数据框变量:
    spline_model <- lm(sales ~ bs(visits, df = 3) + discount, data = data_clean)
    
  • 生成连续预测序列:为visits生成覆盖全范围的连续序列,同时给discount指定固定值(比如均值,或你想观察的特定折扣率):
    visits_seq <- seq(min(data_clean$visits), max(data_clean$visits), length.out = 100) # 生成更平滑的序列
    # 固定discount为均值,也可设为特定值如0.1
    new_data <- data.frame(visits = visits_seq, discount = mean(data_clean$discount))
    
  • 预测拟合值:
    spline_pred <- predict(spline_model, newdata = new_data)
    
  • 绘图:用基础绘图或ggplot2绘制原始点+拟合曲线:
    # 基础绘图
    plot(data_clean$visits, data_clean$sales, main = "观测值 vs 拟合值", xlab = "访问量", ylab = "销售额")
    lines(visits_seq, spline_pred, col = "red", lwd = 3)
    
    # ggplot2版本
    library(ggplot2)
    ggplot(data_clean, aes(x = visits, y = sales)) +
      geom_point(alpha = 0.5) +
      geom_line(data = new_data, aes(y = spline_pred), color = "red", linewidth = 1) +
      labs(title = "观测值 vs 样条拟合曲线", x = "访问量", y = "销售额")
    

2. 为什么需要用seq生成序列+predict绘图,而非直接用原模型?

核心原因有两点:

  • 原始数据离散且分布不均:你的原始visits数据可能存在重复值、稀疏区间,直接用模型对原始数据的拟合值绘图,得到的是零散的点而非平滑曲线,无法直观展示变量间的整体趋势。
  • 样条模型拟合连续关系:样条的核心是捕捉变量间的非线性连续趋势,生成覆盖全范围的连续visits序列,能让模型预测出每个点的拟合值,从而绘制出平滑的趋势曲线,完整展示变量间的非线性关联。

3. 如何绘制3D图展示sales、visits、discount的关联?

可以用plotly包绘制交互式3D曲面图,直观展示三个变量的关系:

library(plotly)

# 生成visits和discount的网格数据
visits_grid <- seq(min(data_clean$visits), max(data_clean$visits), length.out = 50)
discount_grid <- seq(min(data_clean$discount), max(data_clean$discount), length.out = 50)
grid_data <- expand.grid(visits = visits_grid, discount = discount_grid)

# 预测所有网格点的sales值
grid_data$sales_pred <- predict(spline_model, newdata = grid_data)

# 绘制3D曲面图
plot_ly(grid_data, x = ~visits, y = ~discount, z = ~sales_pred) %>%
  add_surface(colorscale = "Viridis") %>%
  add_markers(data = data_clean, x = ~visits, y = ~discount, z = ~sales, 
              marker = list(color = "black", size = 3)) %>%
  layout(scene = list(xaxis = list(title = "访问量"), 
                      yaxis = list(title = "折扣率"), 
                      zaxis = list(title = "销售额")))

这个图会显示样条模型拟合的3D曲面,同时叠加原始数据点,清晰展示两个自变量对因变量的联合影响。


完整修正代码

library(dplyr)
library(splines)
library(ggplot2)
library(plotly)

# 加载数据
data_path <- "https://raw.githubusercontent.com/juanitorduz/website_projects/master/data/sales_dag.csv"
data <- read.csv(data_path)
data_clean <- data %>% select(visits, discount, sales)

# 修正后的样条模型
spline_model <- lm(sales ~ bs(visits, df = 3) + discount, data = data_clean)

# 生成预测序列并绘图(2D)
visits_seq <- seq(min(data_clean$visits), max(data_clean$visits), length.out = 100)
new_data <- data.frame(visits = visits_seq, discount = mean(data_clean$discount))
spline_pred <- predict(spline_model, newdata = new_data)

ggplot(data_clean, aes(x = visits, y = sales)) +
  geom_point(alpha = 0.5) +
  geom_line(data = new_data, aes(y = spline_pred), color = "red", linewidth = 1) +
  labs(title = "观测销售额 vs 样条拟合曲线", x = "网站访问量", y = "销售额")

# 绘制3D关联图
visits_grid <- seq(min(data_clean$visits), max(data_clean$visits), length.out = 50)
discount_grid <- seq(min(data_clean$discount), max(data_clean$discount), length.out = 50)
grid_data <- expand.grid(visits = visits_grid, discount = discount_grid)
grid_data$sales_pred <- predict(spline_model, newdata = grid_data)

plot_ly(grid_data, x = ~visits, y = ~discount, z = ~sales_pred) %>%
  add_surface(colorscale = "Viridis") %>%
  add_markers(data = data_clean, x = ~visits, y = ~discount, z = ~sales, 
              marker = list(color = "black", size = 3)) %>%
  layout(scene = list(xaxis = list(title = "访问量"), 
                      yaxis = list(title = "折扣率"), 
                      zaxis = list(title = "销售额")))

内容的提问来源于stack exchange,提问作者tt33tt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:32:05