【问题标题】:scatterplot3d: regression plane with residualsscatterplot3d:带残差的回归平面
【发布时间】:2018-04-30 21:19:03
【问题描述】:

在 R 中使用scatterplot3d,我试图从观察到回归平面绘制红线:

wh <- iris$Species != "setosa"
x  <- iris$Sepal.Width[wh]
y  <- iris$Sepal.Length[wh]
z  <- iris$Petal.Width[wh]
df <- data.frame(x, y, z)

LM <- lm(y ~ x + z, df)
library(scatterplot3d)
G  <- scatterplot3d(x, z, y, highlight.3d = FALSE, type = "p")
G$plane3d(LM, draw_polygon = TRUE, draw_lines = FALSE)

获得下图的3D等效:

在 2D 中,我可以使用 segments

pred  <- predict(model) 
segments(x, y, x, pred, col = 2)

但在 3D 中我对坐标感到困惑。

【问题讨论】:

    标签: r scatter-plot scatter3d


    【解决方案1】:

    我决定也包含我自己的实现,以防其他人想要使用它。

    回归平面

    require("scatterplot3d")
    
    # Data, linear regression with two explanatory variables
    wh <- iris$Species != "setosa"
    x  <- iris$Sepal.Width[wh]
    y  <- iris$Sepal.Length[wh]
    z  <- iris$Petal.Width[wh]
    df <- data.frame(x, y, z)
    LM <- lm(y ~ x + z, df)
    
    # scatterplot
    s3d <- scatterplot3d(x, z, y, pch = 19, type = "p", color = "darkgrey",
                         main = "Regression Plane", grid = TRUE, box = FALSE,  
                         mar = c(2.5, 2.5, 2, 1.5), angle = 55)
    
    # regression plane
    s3d$plane3d(LM, draw_polygon = TRUE, draw_lines = TRUE, 
                polygon_args = list(col = rgb(.1, .2, .7, .5)))
    
    # overlay positive residuals
    wh <- resid(LM) > 0
    s3d$points3d(x[wh], z[wh], y[wh], pch = 19)
    

    残差

    # scatterplot
    s3d <- scatterplot3d(x, z, y, pch = 19, type = "p", color = "darkgrey",
                         main = "Regression Plane", grid = TRUE, box = FALSE,  
                         mar = c(2.5, 2.5, 2, 1.5), angle = 55)
    
    # compute locations of segments
    orig     <- s3d$xyz.convert(x, z, y)
    plane    <- s3d$xyz.convert(x, z, fitted(LM))
    i.negpos <- 1 + (resid(LM) > 0) # which residuals are above the plane?
    
    # draw residual distances to regression plane
    segments(orig$x, orig$y, plane$x, plane$y, col = "red", lty = c(2, 1)[i.negpos], 
             lwd = 1.5)
    
    # draw the regression plane
    s3d$plane3d(LM, draw_polygon = TRUE, draw_lines = TRUE, 
                polygon_args = list(col = rgb(0.8, 0.8, 0.8, 0.8)))
    
    # redraw positive residuals and segments above the plane
    wh <- resid(LM) > 0
    segments(orig$x[wh], orig$y[wh], plane$x[wh], plane$y[wh], col = "red", lty = 1, lwd = 1.5)
    s3d$points3d(x[wh], z[wh], y[wh], pch = 19)
    


    最终结果:

    虽然我真的很欣赏scatterplot3d 函数的便利性,但最终我还是选择了copying the entire function from github,因为plot 中的几个参数要么被scatterplot3d 强制传递,要么没有正确传递给scatterplot3d(例如使用las 进行轴旋转,使用cex 进行字符扩展,cex.main 等)。我不确定这么长且凌乱的代码块在这里是否合适,所以我将上面的 MWE 包括在内。

    无论如何,这就是我最终包含在我的书中的内容:

    (是的,那其实只是虹膜数据集,不要告诉任何人。)

    【讨论】:

      【解决方案2】:

      使用来自An Introduction to Statistical Learning 的广告数据集,您可以这样做

      advertising_fit1 <- lm(sales~TV+radio, data = advertising)
      sp <- scatterplot3d::scatterplot3d(advertising$TV, 
                                         advertising$radio, 
                                         advertising$sales, 
                                         angle = 45)
      sp$plane3d(advertising_fit1, lty.box = "solid")#,
                 # polygon_args = list(col = rgb(.1, .2, .7, .5)) # Fill color
      orig <- sp$xyz.convert(advertising$TV, 
                             advertising$radio, 
                             advertising$sales)
      plane <- sp$xyz.convert(advertising$TV, 
                              advertising$radio,  fitted(advertising_fit1))
      i.negpos <- 1 + (resid(advertising_fit1) > 0)
      segments(orig$x, orig$y, plane$x, plane$y,
               col = c("blue", "red")[i.negpos], 
               lty = 1) # (2:1)[i.negpos]
      sp <- FactoClass::addgrids3d(advertising$TV, 
                                   advertising$radio, 
                                   advertising$sales,
                                   angle = 45,
                                   grid = c("xy", "xz", "yz"))
      

      还有另一个使用rgl 包的交互式版本

      rgl::plot3d(advertising$TV, 
                   advertising$radio, 
                   advertising$sales, type = "p", 
                   xlab = "TV", 
                   ylab = "radio", 
                   zlab = "Sales", site = 5, lwd = 15)
      rgl::planes3d(advertising_fit1$coefficients["TV"], 
                    advertising_fit1$coefficients["radio"], -1, 
                    advertising_fit1$coefficients["(Intercept)"], alpha = 0.3, front = "line")
      rgl::segments3d(rep(advertising$TV, each = 2), 
                      rep(advertising$radio, each = 2),
                      matrix(t(cbind(advertising$sales, predict(advertising_fit1))), nc = 1),
                      col = c("blue", "red")[i.negpos], 
                      lty = 1) # (2:1)[i.negpos]
      rgl::rgl.postscript("./pics/plot-advertising-rgl.pdf","pdf") # does not really work...
      

      【讨论】:

      • 这太棒了!我最终用一些非常难看的代码解决了这个问题。感谢您提供这个更简单的解决方案,它将使为学生制作示例变得更加容易。
      • @FransRodenburg 查看我的编辑!我可以在第一个版本中填充飞机。如果你找到方法,请告诉我!
      • 当然,我会写我自己的改编作为答案。不幸的是,scatterplot3d 强制使用多个参数,例如 cexcex.maincex.lab、cex.axis`,所以在实际文档中,我最终只是从 github 复制了整个函数并从那里进行了调整。
      猜你喜欢
      • 2017-01-14
      • 1970-01-01
      • 1970-01-01
      • 2017-10-03
      • 2017-03-01
      • 2019-05-15
      • 1970-01-01
      • 2013-05-06
      • 2018-12-07
      相关资源
      最近更新 更多