【问题标题】:How to create a decision boundary graph for kNN models in the Caret package?如何在 Caret 包中为 kNN 模型创建决策边界图?
【发布时间】:2015-12-03 15:15:36
【问题描述】:

我想为 Caret 包创建的模型绘制决策边界。理想情况下,我想要一个适用于 Caret 的任何分类器模型的通用案例方法。但是,我目前正在使用 kNN 方法。我在下面包含了使用 UCI 的葡萄酒质量数据集的代码,这正是我现在正在使用的。

我发现这个方法适用于 R 中的通用 kNN 方法,但不知道如何将其映射到 Caret -> https://stats.stackexchange.com/questions/21572/how-to-plot-decision-boundary-of-a-k-nearest-neighbor-classifier-from-elements-o/21602#21602

    library(caret)

    set.seed(300)

    wine.r <- read.csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv', sep=';')
    wine.w <- read.csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv', sep=';')

    wine.r$style <- "red"
    wine.w$style <- "white"

    wine <- rbind(wine.r, wine.w)

    wine$style <- as.factor(wine$style)

    formula <- as.formula(quality ~ .)

    dummies <- dummyVars(formula, data = wine)
    dummied <- data.frame(predict(dummies, newdata = wine))
    dummied$quality <- wine$quality

    wine <- dummied

    numCols <- !colnames(wine) %in% c('quality', 'style.red', 'style.white')

    low <- wine$quality <= 6
    high <- wine$quality > 6
    wine$quality[low] = "low"
    wine$quality[high] = "high"
    wine$quality <- as.factor(wine$quality)

    indxTrain <- createDataPartition(y = wine[, names(wine) == "quality"], p = 0.7, list = F)

    train <- wine[indxTrain,]
    test <- wine[-indxTrain,]

    corrMat <- cor(train[, numCols])
    correlated <- findCorrelation(corrMat, cutoff = 0.6)

    ctrl <- trainControl(
                         method="repeatedcv",
                         repeats=5,
                         number=10,
                         classProbs = T
                         )

    t1 <- train[, -correlated]
    grid <- expand.grid(.k = c(1:20))

    knnModel <- train(formula, 
                      data = t1, 
                      method = 'knn', 
                      trControl = ctrl, 
                      tuneGrid = grid, 
                      preProcess = 'range'
                      )

    t2 <- test[, -correlated]
    knnPred <- predict(knnModel, newdata = t2)

    # How do I render the decision boundary?

【问题讨论】:

    标签: r machine-learning r-caret graphing


    【解决方案1】:

    第一步是真正了解您链接的代码在做什么!事实上,您可以在与 KNN 无关的情况下生成这样的图。

    例如,让我们只提供一些示例数据,我们只是为数据的下象限“着色”。

    第一步

    生成一个网格。基本上绘图的工作原理是在每个坐标处创建一个点,以便我们知道它属于哪个组。在 R 中,这是使用 expand.grid 完成所有可能的点。

    x1 <- 1:200
    x2 <- 50:250
    
    cgrid <- expand.grid(x1=x1, x2=x2)
    # our "prediction" colours the bottom left quadrant
    cgrid$prob <- 1
    cgrid[cgrid$x1 < 100 & cgrid$x2 < 170, c("prob")] <- 0
    

    如果这是 knn,那么 prob 将是该特定点的预测。

    第 2 步

    现在绘制它相对简单。您需要符合contour 函数,因此您首先创建一个包含概率的矩阵。

    matrix_val <- matrix(cgrid$prob, 
                         length(x1), 
                         length(x2))
    

    第三步

    然后您可以按照链接的操作进行:

    contour(x1, x2, matrix_val, levels=0.5, labels="", xlab="", ylab="", main=
              "Some Picture", lwd=2, axes=FALSE)
    gd <- expand.grid(x=x1, y=x2)
    points(gd, pch=".", cex=1.2, col=ifelse(prob==1, "coral", "cornflowerblue"))
    box()
    

    输出:


    然后回到你的具体例子。我将使用 iris,因为您的数据看起来不是很有趣,但同样的原则也适用。要创建网格,您需要选择 x-y 轴并保持其他所有内容不变!

    knnModel <- train(Species ~., 
                      data = iris, 
                      method = 'knn')
    
    lgrid <- expand.grid(Petal.Length=seq(1, 5, by=0.1), 
                         Petal.Width=seq(0.1, 1.8, by=0.1),
                         Sepal.Length = 5.4,
                         Sepal.Width=3.1)
    

    接下来只需像上面所做的那样使用预测功能。

    knnPredGrid <- predict(knnModel, newdata=lgrid)
    knnPredGrid = as.numeric(knnPredGrid) # 1 2 3
    

    然后构造图:

    pl = seq(1, 5, by=0.1)
    pw = seq(0.1, 1.8, by=0.1)
    
    probs <- matrix(knnPredGrid, length(pl), 
                     length(pw))
    
    contour(pl, pw, probs, labels="", xlab="", ylab="", main=
              "X-nearest neighbour", axes=FALSE)
    
    gd <- expand.grid(x=pl, y=pw)
    
    points(gd, pch=".", cex=5, col=probs)
    box()   
    

    这应该会产生如下输出:


    要从您的模型中添加测试/训练结果,您可以按照我所做的操作。唯一的区别是您需要添加预测点(这与用于生成边界的网格不同。

    library(caret) 
    data(iris)
    
    indxTrain <- createDataPartition(y = iris[, names(iris) == "Species"], p = 0.7, list = F)
    
    train <- iris[indxTrain,]
    test <- iris[-indxTrain,]
    
    knnModel <- train(Species ~.,
                      data = train,
                      method = 'knn')
    
    pl = seq(min(test$Petal.Length), max(test$Petal.Length), by=0.1)
    pw = seq(min(test$Petal.Width), max(test$Petal.Width), by=0.1)
    
    # generates the boundaries for your graph
    lgrid <- expand.grid(Petal.Length=pl, 
                         Petal.Width=pw,
                         Sepal.Length = 5.4,
                         Sepal.Width=3.1)
    
    knnPredGrid <- predict(knnModel, newdata=lgrid)
    knnPredGrid = as.numeric(knnPredGrid)
    
    # get the points from the test data...
    testPred <- predict(knnModel, newdata=test)
    testPred <- as.numeric(testPred)
    # this gets the points for the testPred...
    test$Pred <- testPred
    
    probs <- matrix(knnPredGrid, length(pl), length(pw))
    
    contour(pl, pw, probs, labels="", xlab="", ylab="", main="X-Nearest Neighbor", axes=F)
    gd <- expand.grid(x=pl, y=pw)
    
    points(gd, pch=".", cex=5, col=probs)
    
    # add the test points to the graph
    points(test$Petal.Length, test$Petal.Width, col=test$Pred, cex=2)
    box()
    

    输出:

    您也可以使用ggplot 进行绘图,这可能更容易:

    ggplot(data=lgrid) + stat_contour(aes(x=Petal.Length, y=Petal.Width, z=knnPredGrid),
                                bins=2) +
      geom_point(aes(x=Petal.Length, y=Petal.Width, colour=as.factor(knnPredGrid))) +
      geom_point(data=test, aes(x=test$Petal.Length, y=test$Petal.Width, colour=as.factor(test$Pred)),
                 size=5, alpha=0.5, shape=1)+
      theme_bw()
    

    输出:

    【讨论】:

    • 这是一个非常好的回应,我认为我更接近了。我更新了我的代码要点,试图绘制决策边界:gist.github.com/jameskyle/729945f6fa38a343b8ab。但是我得到的图表是一团糟的格子花呢(i.imgur.com/TYCpleT.png)。这是由于实施中的错误还是数据本身?我选择酒精 + 氯化物作为我的 x,y,因为它们是最重要的特征。
    • 我写了一个基于 iris 的脚本,它对 iris 数据进行分区而不是生成测试集,我得到了一个类似的分数图。我认为这就是决策边界的运作方式?脚本:gist.github.com/jameskyle/ffed976dfef1cbc778d5 图表:i.imgur.com/UX1xmp9.png
    • 在你的newdata部分,数据需要像一个网格;我会更新我的答案。
    • 对于葡萄酒,这是我的代码和输出:gist.github.com/chappers/4881b5ae17918309d184, imgur.com/Ei11k7A
    • 所以 lgrid 用于跨越选定的 x,y 空间,同时保持其他变量不变。因此,模型的预测仅基于感兴趣的两个变量。因此,轮廓是在模型对这两个变量的预测所定义的边界处绘制的。听起来对吗?
    猜你喜欢
    • 2014-03-01
    • 2022-06-16
    • 1970-01-01
    • 2018-04-19
    • 2017-04-12
    • 2015-01-20
    • 2015-02-08
    • 2019-07-31
    • 1970-01-01
    相关资源
    最近更新 更多