如何在 Caret 包中为 kNN 模型创建决策边界图?
How to create a decision boundary graph for kNN models in the Caret package?
我想为 Caret 包创建的模型绘制决策边界。理想情况下,我想要 Caret 中任何分类器模型的通用案例方法。但是,我目前正在使用 kNN 方法。我在下面包含了使用 UCI 的葡萄酒质量数据集的代码,这正是我现在正在使用的。
我发现此方法适用于 R 中的通用 kNN 方法,但无法弄清楚如何将其映射到插入符号 -> 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?
第一步是真正了解您 link 编辑的代码在做什么!实际上,您可以生成这样的图形,而无需使用 KNN。
例如,我们只提供一些示例数据,其中我们只是 "colour" 您数据的下象限。
步骤 1
生成网格。基本上绘图的工作原理是在每个坐标处创建一个点,以便我们知道它属于哪个组。在 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))
步骤 3
然后你可以像link那样继续:
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()
这应该会产生如下输出:
要从您的模型中添加 test/train 结果,您可以按照我所做的操作。唯一的区别是您需要添加预测点(这与用于生成边界的网格不同。
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()
输出:
我想为 Caret 包创建的模型绘制决策边界。理想情况下,我想要 Caret 中任何分类器模型的通用案例方法。但是,我目前正在使用 kNN 方法。我在下面包含了使用 UCI 的葡萄酒质量数据集的代码,这正是我现在正在使用的。
我发现此方法适用于 R 中的通用 kNN 方法,但无法弄清楚如何将其映射到插入符号 -> 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?
第一步是真正了解您 link 编辑的代码在做什么!实际上,您可以生成这样的图形,而无需使用 KNN。
例如,我们只提供一些示例数据,其中我们只是 "colour" 您数据的下象限。
步骤 1
生成网格。基本上绘图的工作原理是在每个坐标处创建一个点,以便我们知道它属于哪个组。在 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))
步骤 3
然后你可以像link那样继续:
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()
这应该会产生如下输出:
要从您的模型中添加 test/train 结果,您可以按照我所做的操作。唯一的区别是您需要添加预测点(这与用于生成边界的网格不同。
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()
输出: