2015-09-08 6 views
5

Chciałbym wykreślić granicę decyzji dla modelu utworzonego przez pakiet Caret. Idealnie, chciałbym ogólnej metody dla każdego modelu klasyfikatora z Caret. Jednak obecnie pracuję z metodą kNN. Poniżej zamieściłem poniższy kod, który używa zbioru danych o jakości wina z UCI, z którym właśnie pracuję.Jak utworzyć wykres granicy decyzji dla modeli kNN w pakiecie Caret?

znalazłem tę metodę, która współpracuje z ogólnym sposobem KNN w badania, ale nie można dowiedzieć się, jak mapować go 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? 

Odpowiedz

5

Pierwszym krokiem jest, aby zrozumieć, co faktycznie kod jesteś połączony! Rzeczywiście, możesz wyprodukować taki wykres, który nie ma nic wspólnego z KNN.

Na przykład, poprostu mamy przykładowe dane, w których po prostu "kolorujemy" dolny kwadrant danych.

Krok 1

Generowanie siatki. Zasadniczo, jak działa wykres, należy utworzyć punkt na każdej współrzędnej, abyśmy wiedzieli, do której grupy należy. w R jest to wykonywane przy użyciu expand.grid, aby przejść przez wszystkie możliwe punkty.

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 

Jeśli ta została KNN, byłoby prob byłoby przewidywanie dla danego punktu.

Krok 2

Teraz kreślenia jest stosunkowo proste. Musisz dostosować się do funkcji contour, aby najpierw utworzyć macierz z prawdopodobieństwami.

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

Krok 3

Następnie można przystąpić jak to, co zrobił 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() 

wyjściowa:

somepic


Więc wróć do swojego konkretnego przykładu. Zamierzam użyć tęczówki, ponieważ twoje dane nie były zbyt interesujące, ale ta sama zasada obowiązuje. Aby utworzyć siatkę, musisz wybrać oś X-Y i pozostawić wszystko inne na stałe!

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) 

Następnie wystarczy użyć funkcji przewidywania, tak jak to zrobiono powyżej.

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

A potem skonstruować wykresu:

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() 

ta powinna przynieść wyjście tak:

iris


Aby dodać wyniki testu/pociąg od modelu, możesz śledzić to, co zrobiłem. Jedyną różnicą jest to, czego potrzebujesz, aby dodać przewidywanych punktów (to nie jest taka sama jak siatki, które zostały użyte do wygenerowania granicę

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() 

wyjściowa:.

enter image description here

Alternatywnie można użyć ggplot zrobić wykresów, które mogłyby być łatwiejsze:

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() 

wyjściowa:

enter image description here

+0

To bardzo dobra odpowiedź i jestem o wiele bliżej, myślę. Zaktualizowałem istotę mojego kodu, próbując wykreślić granicę decyzji: https://gist.github.com/jameskyle/729945f6fa38a343b8ab. Ale wykres, który dostaję, jest potwornym, plaid mess (http://i.imgur.com/TYCpleT.png). Czy przyczyną jest błąd w implementacji, czy też same dane? Wybrałem alkohole i chlorki jako moje x, y, ponieważ były to cechy najwyższej wagi. –

+0

Napisałem skrypt oparty na irysie, który dzieli dane tęczówki zamiast generować zestaw testowy, otrzymuję podobnie ułamkowy wykres. Zakładam, że tak właśnie działają granice decyzyjne? Skrypt: https://gist.github.com/jameskyle/ffed976dfef1cbc778d5 Wykres: http://i.imgur.com/UX1xmp9.png –

+0

W części newdata dane muszą być podobne do siatki; Zaktualizuję moją odpowiedź. – chappers

Powiązane problemy