如何从 R 中的 3D 图中的分类算法绘制分区平面

How do you draw a partition plane from a classification algorithm in a 3D plot in R

我正在尝试从 R 中的 3D 绘图中的分类算法绘制分区边界(使用 plot3D)。如果我们只有两个预测变量,这将是一个相对简单的任务,只需要绘制两个轴(例如使用 partimat 函数)。我还没有找到在 3D 中绘制基于三个预测变量的分类分区的令人满意的方法 space。

为了使问题可视化,让我们首先在 iris 数据集上使用线性判别分析 (LDA) 分类算法为两个轴构建一个分区:

# Load packages and subset the iris dataset:
library(klaR)

data = droplevels(iris[iris$Species != 'virginica', ])

partimat(Species ~ Sepal.Length + Sepal.Width, data, 
         method = 'lda')

我们得到一个二维图,其中两个物种之间有明确定义的分区:

但是,partimat 一次只能处理两个预测变量(参见 ?partimat)。现在让我们看一下3D问题:

library(plot3D)
    
# Plot the raw data:
points3D(data$Sepal.Length, data$Sepal.Width, data$Petal.Length,
             colkey = F,
             pch = 16, cex = 2,
             theta = 30, phi = 30, 
             ticktype = 'detailed',
             col = data$Species)

我想根据像 LDA 这样的分类算法绘制一个平面来分隔两个数据 类。从 中汲取灵感,这是我定义三个预测变量之间的分区的糟糕尝试。本质上,我已经建立了一个具有三个预测变量的 LDA 模型,然后将物种(setosa 或 versicolor)预测到最大值之间的多个点上。和分钟。所有三个预测变量的值。当绘制在 3D 图上时,这会生成一个点云,以不同的颜色表示 3D space 根据三个预测变量应该出现任何一种鸢尾花的位置:

# Build a classification model with three predictors:
m = lda(Species ~ Sepal.Length + Sepal.Width + Petal.Length, data)

# Predict 'Species' for the full range of each plant metric: 
np = 50

nx = seq(from = min(data[, 1]), to = max(data[, 1]), length.out = np)
ny = seq(from = min(data[, 2]), to = max(data[, 2]), length.out = np)
nz = seq(from = min(data[, 3]), to = max(data[, 3]), length.out = np)
nd = expand.grid(Sepal.Length = nx, Sepal.Width = ny, Petal.Length = nz)

p    = as.numeric(predict(m, newdata = nd)$class)
part = cbind(nd, Partition = p)

# Plot the partition and add the data points:  
scatter3D(part$Sepal.Length, part$Sepal.Width, part$Petal.Length, 
          colvar = part$Partition, 
          colkey = F,
          alpha = 0.5,
          pch = 16, cex = 0.3, 
          theta = 30, phi = 30, 
          ticktype = 'detailed',
          plot = F)
points3D(data$Sepal.Length, data$Sepal.Width, data$Petal.Length,
         colkey = F,
         pch = 16, cex = 2,
         theta = 30, phi = 30, 
         ticktype = 'detailed',
         col = data$Species,
         add = T)

我还添加了数据点。您可以将分区视为点云中蓝色和红色之间的模糊交集:

这不是一个理想的解决方案,因为很难看到隐藏在点云中的数据点。点云也有点让人分心。也许一些巧妙地绘制具有透明度的点会有所改善,但我怀疑更好的解决方案是在物种 类 之间的交点处绘制一个平面(类似于 regression plane)(即蓝点和红点相遇)。请注意,我最终希望使用不同的分类器(例如随机森林),以防万一存在仅限于 LDA 或类似的解决方案。

非常感谢任何解决方案或建议。

您可以使用 lda 模型中的系数来生成分隔判别体积的平面。实际上,平面是 3D space 中的一组点,其中 (x, y, z) 坐标乘以它们各自的模型系数的总和等于模型的阈值(即平面模型无法将一组与另一组区分开来)。

我们可以通过创建一个 10 x 10 的网格来做到这一点,其中 spaced 个值沿 x 轴和 y 轴相等,并计算 z 值,该值为我们提供基于模型的阈值:

threshold <-  sum(coef(m) * data[1, 1:3]) - predict(m)$x[1] 

Sepal_Lengths <- seq(min(data$Sepal.Length), max(data$Sepal.Length), length.out = 10)
Sepal_Widths  <- seq(min(data$Sepal.Width), max(data$Sepal.Width), length.out = 10)
Petal_Lengths <- outer(Sepal_Lengths, Sepal_Widths, function(x, y) {
                  (threshold - x * coef(m)[1] - y * coef(m)[2]) / coef(m)[3]})

所以现在当我们得出我们的观点时:

points3D(data$Sepal.Length, data$Sepal.Width, data$Petal.Length,
         colkey = F,
         pch = 16, cex = 2,
         theta = 30, phi = 30, 
         ticktype = 'detailed',
         col = data$Species)

添加平面非常简单:

persp3D(x = Sepal_Lengths, 
        y = Sepal_Widths, 
        z = Petal_Lengths, 
        col = "gold", add = TRUE, alpha = 0.5)