Come tracciare il confine decisionale di un classificatore k vicino più vicino da Elements of Statistical Learning?


31

Voglio generare la trama descritta nel libro ElemStatLearn "Gli elementi dell'apprendimento statistico: data mining, inferenza e previsione. Seconda edizione" di Trevor Hastie, Robert Tibshirani e Jerome Friedman. La trama è:

inserisci qui la descrizione dell'immagine

Mi chiedo come posso produrre questo grafico esatto R, in particolare notare la griglia grafica e il calcolo per mostrare il confine.



1
@StasK: sì, lo è. Come generare la trama? Per favore, potresti aiutarmi? Grazie molto!
littleEinstein,

Risposte:


35

Per riprodurre questa figura, devi avere il pacchetto ElemStatLearn installato sul tuo sistema. Il set di dati artificiale è stato generato mixture.example()come indicato da @StasK.

library(ElemStatLearn)
require(class)
x <- mixture.example$x
g <- mixture.example$y
xnew <- mixture.example$xnew
mod15 <- knn(x, xnew, g, k=15, prob=TRUE)
prob <- attr(mod15, "prob")
prob <- ifelse(mod15=="1", prob, 1-prob)
px1 <- mixture.example$px1
px2 <- mixture.example$px2
prob15 <- matrix(prob, length(px1), length(px2))
par(mar=rep(2,4))
contour(px1, px2, prob15, levels=0.5, labels="", xlab="", ylab="", main=
        "15-nearest neighbour", axes=FALSE)
points(x, col=ifelse(g==1, "coral", "cornflowerblue"))
gd <- expand.grid(x=px1, y=px2)
points(gd, pch=".", cex=1.2, col=ifelse(prob15>0.5, "coral", "cornflowerblue"))
box()

Tutti tranne gli ultimi tre comandi provengono dalla guida in linea per mixture.example. Tieni presente che abbiamo utilizzato il fatto che expand.gridorganizzerà il suo output variando xprima, il che consente inoltre di indicizzare (per colonna) i colori nella prob15matrice (di dimensione 69x99), che detiene la proporzione dei voti per la classe vincente per ciascuna coordinate reticolari ( px1, px2).

inserisci qui la descrizione dell'immagine


+1. Grazie! Mi chiedo anche come generare i dati come descritto nel testo "esporre l'oracolo". Potresti anche aggiungerlo, invece di utilizzare i dati dal sito Web?
littleEinstein,

@littleEinstein Intendi cosa viene dato nella guida in linea per mixture.example? Guarda l'impostazione di simulazione sotto la riga che inizia con # Reproducing figure 2.4, page 17 of the book:nella sezione di esempio.
chl

puoi per favore fatemi sapere il link? Non riesco a trovarlo.
littleEinstein,

Scusate @littleEinstein, ma probabilmente mi manca qualcosa. Si tratta solo di digitare help(mixture.example)o example(mixture.example)al prompt R (dopo aver caricato il pacchetto richiesto con library(ElemStatLearn)). Il codice per generare il set di dati artificiale (per non generare la Fig. 2.4) è scritto in semplice R nella sezione Esempio.
chl

1
A proposito, mi sono appena imbattuto nel weblog di @ Shane dove ha usato ggplotper scopi simili. Dai un'occhiata a questo: ESL 2.1: regressione lineare vs. KNN .
chl

7

Sto imparando da sola ESL e sto cercando di elaborare tutti gli esempi forniti nel libro. Ho appena fatto questo e puoi controllare il codice R qui sotto:

library(MASS)
# set the seed to reproduce data generation in the future
seed <- 123456
set.seed(seed)

# generate two classes means
Sigma <- matrix(c(1,0,0,1),nrow = 2, ncol = 2)
means_1 <- mvrnorm(n = 10, mu = c(1,0), Sigma)
means_2 <- mvrnorm(n = 10, mu = c(0,1), Sigma)

# pick an m_k at random with probability 1/10
# function to generate observations
genObs <- function(classMean, classSigma, size, ...)
{
  # check input
  if(!is.matrix(classMean)) stop("classMean should be a matrix")
  nc <- ncol(classMean)
  nr <- nrow(classMean)
  if(nc != 2) stop("classMean should be a matrix with 2 columns")
  if(ncol(classSigma) != 2) stop("the dimension of classSigma is wrong")

  # mean for each obs
    # pick an m_k at random
  meanObs <- classMean[sample(1:nr, size = size, replace = TRUE),]
  obs <- t(apply(meanObs, 1, function(x) mvrnorm(n = 1, mu = x, Sigma = classSigma )) )
  colnames(obs) <- c('x1','x2')
  return(obs)
}


obs100_1 <- genObs(classMean = means_1, classSigma = Sigma/5, size = 100)
obs100_2 <- genObs(classMean = means_2, classSigma = Sigma/5, size = 100)

# generate label
y <- rep(c(0,1), each = 100)

# training data matrix
trainMat <- as.data.frame(cbind(y, rbind(obs100_1, obs100_2)))

# plot them
library(lattice)
with(trainMat, xyplot(x2 ~ x1,groups = y, col=c('blue', 'orange')))

# now fit two models

# model 1: linear regression
lmfits <- lm(y ~ x1 + x2 , data = trainMat)

# get the slope and intercept for the decision boundary
intercept <- -(lmfits$coef[1] - 0.5) / lmfits$coef[3]
slope <- - lmfits$coef[2] / lmfits$coef[3]

# Figure 2.1
xyplot(x2 ~ x1, groups = y, col = c('blue', 'orange'), data = trainMat,
       panel = function(...)
       {
        panel.xyplot(...)
        panel.abline(intercept, slope)
        },
       main = 'Linear Regression of 0/1 Response')    

# model2: k nearest-neighbor methods
library(class)
# get the range of x1 and x2
rx1 <- range(trainMat$x1)
rx2 <- range(trainMat$x2)
# get lattice points in predictor space
px1 <- seq(from = rx1[1], to = rx1[2], by = 0.1 )
px2 <- seq(from = rx2[1], to = rx2[2], by = 0.1 )
xnew <- expand.grid(x1 = px1, x2 = px2)

# get the contour map
knn15 <- knn(train = trainMat[,2:3], test = xnew, cl = trainMat[,1], k = 15, prob = TRUE)
prob <- attr(knn15, "prob")
prob <- ifelse(knn15=="1", prob, 1-prob)
prob15 <- matrix(prob, nrow = length(px1), ncol = length(px2))

# Figure 2.2
par(mar = rep(2,4))
contour(px1, px2, prob15, levels=0.5, labels="", xlab="", ylab="", main=
    "15-nearest neighbour", axes=FALSE)
points(trainMat[,2:3], col=ifelse(trainMat[,1]==1, "coral", "cornflowerblue"))
points(xnew, pch=".", cex=1.2, col=ifelse(prob15>0.5, "coral", "cornflowerblue"))
box()

1
Per inserire il codice qui senza farlo, puoi evidenziare il testo che è codice e quindi fare clic sul pulsante "codice" nella parte superiore della pagina. È in una fila di icone / pulsanti. Il codice sembra un apparecchio.
Peter Flom - Ripristina Monica

Ri: "come incollare un blocco di codice R". Hai accesso a una piccola barra dei menu quando modifichi il tuo post.
chl

Inoltre, se non stai utilizzando un editor in grado di indentare facilmente blocchi di codice, penso che sarai felice di passare a uno. Ad esempio in Rstudio selezionando il codice e premendo la linguetta si rientra, in modo che sia possibile 5>>, ecc.
Segna il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.