2011-09-13 8 views
13

¿Cómo dividir automáticamente una matriz usando R para 5 veces la validación cruzada? En realidad, quiero generar los 5 conjuntos de (test_matrix_indices, train matrix_indices).Generar conjuntos para la validación cruzada

+0

No mezcle las respuestas a su pregunta. Esto se vuelve confuso. Si quiere responder su propia pregunta, hágalo en una nueva respuesta. – Andrie

+0

Para la validación cruzada en K, tiene que combinar subconjuntos K-1 como conjunto de entrenamiento y dejar uno como prueba (repetirlo K veces), por lo que esta no es una solución completa para su problema. –

+0

He puesto mi respuesta en la sección de respuestas. – Delphine

Respuesta

15
f_K_fold <- function(Nobs,K=5){ 
    rs <- runif(Nobs) 
    id <- seq(Nobs)[order(rs)] 
    k <- as.integer(Nobs*seq(1,K-1)/K) 
    k <- matrix(c(0,rep(k,each=2),Nobs),ncol=2,byrow=TRUE) 
    k[,1] <- k[,1]+1 
    l <- lapply(seq.int(K),function(x,k,d) 
       list(train=d[!(seq(d) %in% seq(k[x,1],k[x,2]))], 
        test=d[seq(k[x,1],k[x,2])]),k=k,d=id) 
    return(l) 
} 
+0

Es una solución elegante. Gracias. – Delphine

+0

Además, esta solución puede volverse determinista agregando set.seed (n) – Delphine

+2

¿qué id d? No lo entiendo – LoveMeow

23

Supongo que quiere que las filas de la matriz sean los casos para dividir. Entonces todo lo que necesita es sample y split:

X <- matrix(rnorm(1000),ncol=5) 
id <- sample(1:5,nrow(X),replace=TRUE) 
ListX <- split(x,id) # gives you a list with the 5 matrices 
X[id==2,] # gives you the second matrix 

que trabajaría con la lista, ya que le permite hacer algo como:

names(ListX) <- c("Train1","Train2","Train3","Test1","Test2") 
mean(ListX$Train3) 

que lo convierte en código que es más fácil de leer, y le impide crear toneladas de matrices en su espacio de trabajo. Es inevitable que se equivoque si coloca las matrices individualmente en su área de trabajo. Use listas!

En caso de que quiera la matriz de prueba sea menor o mayor que los demás, utiliza el argumento prob de sample:

id <- sample(1:5,nrow(X),replace=TRUE,prob=c(0.15,0.15,0.15,0.15,0.3)) 

le da una matriz de prueba que es el doble del tamaño de las matrices de tren.

En caso de que quiera determinar el número exacto de casos, sample y prob no son las mejores opciones. Puede usar un truco como:

indices <- rep(1:5,c(100,20,20,20,40)) 
id <- sample(indices) 

para obtener matrices con respectivamente 100, 20, ... y 40 casos.

+0

+1 por división: en realidad, me he estado preguntando acerca de cómo generar matrices para la validación cruzada, y esto es perfecto. – richiemorrisroe

+0

joris gran código gracias. ¿No es la idea con la validación cruzada que recorre todos los conjuntos y utiliza cada grupo como datos de prueba al menos una vez, lo que frustraría el propósito de usar la lista y nombrarla como usted? – appleLover

+0

@appleLover El uso de listas es meramente para evitar tener que generar matrices individuales en su espacio de trabajo. Es para mantener todo unido. Existen múltiples enfoques para la validación cruzada y el arranque, y dependiendo del enfoque necesitará diferentes correcciones en sus estadísticas. Acabo de dar un método para crear esas matrices de una manera organizada. –

4

solución sin dividir:

set.seed(7402313) 
X <- matrix(rnorm(999), ncol=3) 
k <- 5 # number of folds 

# Generating random indices 
id <- sample(rep(seq_len(k), length.out=nrow(X))) 
table(id) 
# 1 2 3 4 5 
# 67 67 67 66 66 

# lapply over them: 
indicies <- lapply(seq_len(k), function(a) list(
    test_matrix_indices = which(id==a), 
    train_matrix_indices = which(id!=a) 
)) 
str(indicies) 
# List of 5 
# $ :List of 2 
# ..$ test_matrix_indices : int [1:67] 12 13 14 17 18 20 23 28 41 45 ... 
# ..$ train_matrix_indices: int [1:266] 1 2 3 4 5 6 7 8 9 10 ... 
# $ :List of 2 
# ..$ test_matrix_indices : int [1:67] 4 19 31 36 47 53 58 67 83 89 ... 
# ..$ train_matrix_indices: int [1:266] 1 2 3 5 6 7 8 9 10 11 ... 
# $ :List of 2 
# ..$ test_matrix_indices : int [1:67] 5 8 9 30 32 35 37 56 59 60 ... 
# ..$ train_matrix_indices: int [1:266] 1 2 3 4 6 7 10 11 12 13 ... 
# $ :List of 2 
# ..$ test_matrix_indices : int [1:66] 1 2 3 6 21 24 27 29 33 34 ... 
# ..$ train_matrix_indices: int [1:267] 4 5 7 8 9 10 11 12 13 14 ... 
# $ :List of 2 
# ..$ test_matrix_indices : int [1:66] 7 10 11 15 16 22 25 26 40 42 ... 
# ..$ train_matrix_indices: int [1:267] 1 2 3 4 5 6 8 9 12 13 ... 

Pero se puede devolver matrices también:

matrices <- lapply(seq_len(k), function(a) list(
    test_matrix = X[id==a, ], 
    train_matrix = X[id!=a, ] 
)) 
str(matrices) 
List of 5 
# $ :List of 2 
    # ..$ test_matrix : num [1:67, 1:3] -1.0132 -1.3657 -0.3495 0.6664 0.0762 ... 
    # ..$ train_matrix: num [1:266, 1:3] -0.65 0.797 0.689 0.484 0.682 ... 
# $ :List of 2 
    # ..$ test_matrix : num [1:67, 1:3] 0.484 0.418 -0.622 0.996 0.414 ... 
    # ..$ train_matrix: num [1:266, 1:3] -0.65 0.797 0.689 0.682 0.186 ... 
# $ :List of 2 
    # ..$ test_matrix : num [1:67, 1:3] 0.682 0.812 -1.111 -0.467 0.37 ... 
    # ..$ train_matrix: num [1:266, 1:3] -0.65 0.797 0.689 0.484 0.186 ... 
# $ :List of 2 
    # ..$ test_matrix : num [1:66, 1:3] -0.65 0.797 0.689 0.186 -1.398 ... 
    # ..$ train_matrix: num [1:267, 1:3] 0.484 0.682 0.473 0.812 -1.111 ... 
# $ :List of 2 
    # ..$ test_matrix : num [1:66, 1:3] 0.473 0.212 -2.175 -0.746 1.707 ... 
    # ..$ train_matrix: num [1:267, 1:3] -0.65 0.797 0.689 0.484 0.682 ... 

entonces se podría utilizar lapply para obtener resultados:

lapply(matrices, function(x) { 
    m <- build_model(x$train_matrix) 
    performance(m, x$test_matrix) 
}) 

Edición: comparar con Wojc La solución de IECH:

f_K_fold <- function(Nobs, K=5){ 
    id <- sample(rep(seq.int(K), length.out=Nobs)) 
    l <- lapply(seq.int(K), function(x) list(
     train = which(x!=id), 
     test = which(x==id) 
    )) 
    return(l) 
} 
0

Edit: Gracias por sus respuestas. he encontrado la siguiente solución (http://eric.univ-lyon2.fr/~ricco/tanagra/fichiers/fr_Tanagra_Validation_Croisee_Suite.pdf):

n <- nrow(mydata) 
K <- 5 
size <- n %/% K 
set.seed(5) 
rdm <- runif(n) 
ranked <- rank(rdm) 
block <- (ranked-1) %/% size+1 
block <- as.factor(block) 

Luego uso:

for (k in 1:K) { 
    matrix_train<-matrix[block!=k,] 
    matrix_test<-matrix[block==k,] 
    [Algorithm sequence] 
    } 

para generar los conjuntos adecuados para cada iteración.

Sin embargo, esta solución puede omitir un individuo para las pruebas. No lo recomiendo.

0

A continuación se explica el truco sin tener que crear separadamente data.frames/matrices, todo lo que necesita hacer es mantener un entero sequnce, id que almacena los índices mezclados para cada pliegue.

X <- read.csv('data.csv') 

k = 5 # number of folds 
fold_size <-nrow(X)/k 
indices <- rep(1:k,rep(fold_size,k)) 
id <- sample(indices, replace = FALSE) # random draws without replacement 

log_models <- new.env(hash=T, parent=emptyenv()) 
for (i in 1:k){ 
    train <- X[id != i,] 
    test <- X[id == i,] 
    # run algorithm, e.g. logistic regression 
    log_models[[as.character(i)]] <- glm(outcome~., family="binomial", data=train) 
} 
+0

Tenga en cuenta que cuando nrow (X) no es un múltiplo de k, algunas muestras se descartan. – Samuel

0

El paquete sperrorest proporciona esta posibilidad. Puede elegir entre una división aleatoria (partition.cv()), una división espacial (partition.kmeans()) o una división basada en niveles de factor (partition.factor.cv()). Actualmente, este último solo está disponible en la versión Github.

Ejemplo:

library(sperrorest) 
data(ecuador) 

## non-spatial cross-validation: 
resamp <- partition.cv(ecuador, nfold = 5, repetition = 1:1) 

# first repetition, second fold, test set indices: 
idx <- resamp[['1']][[2]]$test 

# test sample used in this particular repetition and fold: 
ecuador[idx , ] 

Si usted tiene un conjunto de datos espaciales (con coord), también se puede visualizar sus pliegues generados

# this may take some time... 
plot(resamp, ecuador) 

enter image description here

La validación cruzada puede ser entonces realizado usando sperrorest() (secuencial) o parsperrorest() (paralelo).

Cuestiones relacionadas