Cómo dividir datos en conjuntos de entrenamiento / prueba usando la función de muestra

160

Acabo de comenzar a usar R y no estoy seguro de cómo incorporar mi conjunto de datos con el siguiente código de muestra:

sample(x, size, replace = FALSE, prob = NULL)

Tengo un conjunto de datos que necesito poner en un conjunto de entrenamiento (75%) y pruebas (25%). No estoy seguro de qué información debo poner en la x y el tamaño. ¿Es x el archivo del conjunto de datos y el tamaño de cuántas muestras tengo?

Susie Humby
fuente
1
xpuede ser el índice (fila / col nos. decir) de su data. sizepuede ser 0.75*nrow(data). Intenta sample(1:10, 4, replace = FALSE, prob = NULL)ver qué hace.
harkmug

Respuestas:

255

Existen numerosos enfoques para lograr la partición de datos. Para un enfoque más completo, eche un vistazo a la createDataPartitionfunción en el caToolspaquete.

Aquí hay un ejemplo simple:

data(mtcars)

## 75% of the sample size
smp_size <- floor(0.75 * nrow(mtcars))

## set the seed to make your partition reproducible
set.seed(123)
train_ind <- sample(seq_len(nrow(mtcars)), size = smp_size)

train <- mtcars[train_ind, ]
test <- mtcars[-train_ind, ]
dickoa
fuente
Estoy un poco confundido, ¿qué garantiza que este código devuelva una prueba única y un df de entrenamiento? Parece funcionar, no me malinterpretes. Simplemente tener problemas para entender cómo restar los índices conduce a observaciones únicas. Por ejemplo, si tenía un df con 10 filas y una columna, y la columna contenía 1,2,3,4,5,6,7,8,9,10 y siguió este código, lo que impide que un tren tenga índice 4 y prueba con -6 -> 10 - 6 = 4 también?
goldisfine 05 de
1
gracias. Lo intenté mtcars[!train_ind]y aunque no falló, no funcionó como se esperaba. ¿Cómo podría subconjunto usando el !?
user989762
@ user989762 !se usan para lógico ( TRUE/FALSE) y no para índices. Si desea usar un subconjunto !, intente algo como mtcars [ !seq_len(nrow(mtcars)) %in% train_ind,] (no probado).
dickoa
1
@VedaadShakib cuando usa "-" omite todo el índice en train_ind de sus datos. Echa un vistazo a adv-r.had.co.nz/Subsetting.html . Espero que ayude
dickoa
1
¿No está createDataPartitionadentro carety no caTools?
J. Mini
93

Se puede hacer fácilmente mediante:

set.seed(101) # Set Seed so that same sample can be reproduced in future also
# Now Selecting 75% of data as sample from total 'n' rows of the data  
sample <- sample.int(n = nrow(data), size = floor(.75*nrow(data)), replace = F)
train <- data[sample, ]
test  <- data[-sample, ]

Al usar el paquete caTools :

require(caTools)
set.seed(101) 
sample = sample.split(data$anycolumn, SplitRatio = .75)
train = subset(data, sample == TRUE)
test  = subset(data, sample == FALSE)
TheMI
fuente
44
Recientemente hice un curso con MIT y utilizaron el enfoque usando caTools en todo momento. Gracias
Chetan Sharma
1
sample = sample.split(data[,1], SplitRatio = .75)Debe eliminar la necesidad de nombrar una columna.
Benjamin Ziepert
33

Lo usaría dplyrpara esto, lo hace súper simple. Requiere una variable de identificación en su conjunto de datos, lo cual es una buena idea de todos modos, no solo para crear conjuntos sino también para la trazabilidad durante su proyecto. Agréguelo si aún no lo contiene.

mtcars$id <- 1:nrow(mtcars)
train <- mtcars %>% dplyr::sample_frac(.75)
test  <- dplyr::anti_join(mtcars, train, by = 'id')
Edwin
fuente
28

Este es casi el mismo código, pero en un aspecto más agradable

bound <- floor((nrow(df)/4)*3)         #define % of training and test set

df <- df[sample(nrow(df)), ]           #sample rows 
df.train <- df[1:bound, ]              #get training set
df.test <- df[(bound+1):nrow(df), ]    #get test set
Katerina
fuente
¡Sip! ¡Bonito estilo!
MeenakshiSundharam
23
library(caret)
intrain<-createDataPartition(y=sub_train$classe,p=0.7,list=FALSE)
training<-m_train[intrain,]
testing<-m_train[-intrain,]
pradnya chavan
fuente
3
Si bien una respuesta de solo código es una respuesta, es mejor proporcionar alguna explicación.
C8H10N4O2
¿Qué es m_train? Creo que quisiste decir, subentrenar el data.frame original. Por lo tanto, el código revisado debe ser entrenamiento <-sub_train [intrain,] y prueba <-sub_train [-intrain,]. ¡Me pregunto por qué nadie pudo detectar este gran problema con su respuesta en los últimos cinco años!
mnm
21

Dividiré 'a' en tren (70%) y prueba (30%)

    a # original data frame
    library(dplyr)
    train<-sample_frac(a, 0.7)
    sid<-as.numeric(rownames(train)) # because rownames() returns character
    test<-a[-sid,]

hecho

hyunwoo jeong
fuente
44
necesita importar el paquete dpyr, requiere (dplyr)
TheMI
Esta respuesta me ayudó, pero necesitaba ajustarla para obtener los resultados esperados. Como es, el conjunto de datos 'train' tiene nombres de fila = sid de enteros secuenciales: 1,2,3,4, ... mientras que desea que sid sean los números de rown del conjunto de datos original 'a', que como se seleccionaron al azar ganó sean los enteros secuenciales. Por lo tanto, primero es necesario crear la variable id en 'a'.
Scott Murff
row.names (mtcars) <- NULL; train <-dplyr :: sample_frac (mtcars, 0.5); prueba <-mtcars [-as.numeric (row.names (train)),] # Hice esto con mis datos, el código original no funciona si los nombres de sus filas ya están configurados en números
Christopher John
16

Mi solución es básicamente la misma que la de dickoa pero un poco más fácil de interpretar:

data(mtcars)
n = nrow(mtcars)
trainIndex = sample(1:n, size = round(0.7*n), replace=FALSE)
train = mtcars[trainIndex ,]
test = mtcars[-trainIndex ,]
AlexG
fuente
¿Cuál es la variable suiza?
billmccord
7

Solo una manera más breve y simple usando la impresionante biblioteca dplyr :

library(dplyr)
set.seed(275) #to get repeatable data

data.train <- sample_frac(Default, 0.7)

train_index <- as.numeric(rownames(data.train))
data.test <- Default[-train_index, ]
Shayan Amani
fuente
1
¿Querías usar Default[-train_index,]para la última línea?
Matt L.
5

Si escribes:

?sample

If lanzará un menú de ayuda para explicar qué significan los parámetros de la función de muestra.

No soy un experto, pero aquí hay un código que tengo:

data <- data.frame(matrix(rnorm(400), nrow=100))
splitdata <- split(data[1:nrow(data),],sample(rep(1:4,as.integer(nrow(data)/4))))
test <- splitdata[[1]]
train <- rbind(splitdata[[1]],splitdata[[2]],splitdata[[3]])

Esto te dará un 75% de entrenamiento y un 25% de prueba.

user2502836
fuente
5

Después de revisar todos los diferentes métodos publicados aquí, no vi a nadie utilizar TRUE/FALSEpara seleccionar y anular la selección de datos. Así que pensé en compartir un método utilizando esa técnica.

n = nrow(dataset)
split = sample(c(TRUE, FALSE), n, replace=TRUE, prob=c(0.75, 0.25))

training = dataset[split, ]
testing = dataset[!split, ]

Explicación

Existen múltiples formas de seleccionar datos de R, la mayoría de las personas usan índices positivos / negativos para seleccionar / deseleccionar respectivamente. Sin embargo, se pueden lograr las mismas funcionalidades usando TRUE/FALSEpara seleccionar / deseleccionar.

Considere el siguiente ejemplo.

# let's explore ways to select every other element
data = c(1, 2, 3, 4, 5)


# using positive indices to select wanted elements
data[c(1, 3, 5)]
[1] 1 3 5

# using negative indices to remove unwanted elements
data[c(-2, -4)]
[1] 1 3 5

# using booleans to select wanted elements
data[c(TRUE, FALSE, TRUE, FALSE, TRUE)]
[1] 1 3 5

# R recycles the TRUE/FALSE vector if it is not the correct dimension
data[c(TRUE, FALSE)]
[1] 1 3 5
Joe
fuente
4

Mi solución baraja las filas, luego toma el primer 75% de las filas como tren y el último 25% como prueba. Súper simples!

row_count <- nrow(orders_pivotted)
shuffled_rows <- sample(row_count)
train <- orders_pivotted[head(shuffled_rows,floor(row_count*0.75)),]
test <- orders_pivotted[tail(shuffled_rows,floor(row_count*0.25)),]
Johnny V
fuente
4

Puedo sugerirle que use el paquete rsample:

# choosing 75% of the data to be the training data
data_split <- initial_split(data, prop = .75)
# extracting training data and test data as two seperate dataframes
data_train <- training(data_split)
data_test  <- testing(data_split)

fuente
3

scorecard El paquete tiene una función útil para eso, donde puede especificar la relación y la semilla

library(scorecard)

dt_list <- split_df(mtcars, ratio = 0.75, seed = 66)

Los datos de prueba y tren se almacenan en una lista y se puede acceder llamando dt_list$trainydt_list$test

camnesia
fuente
2

Debajo de una función que crea una listde submuestras del mismo tamaño que no es exactamente lo que quería pero podría resultar útil para otros. En mi caso, para crear múltiples árboles de clasificación en muestras más pequeñas para probar el sobreajuste:

df_split <- function (df, number){
  sizedf      <- length(df[,1])
  bound       <- sizedf/number
  list        <- list() 
  for (i in 1:number){
    list[i] <- list(df[((i*bound+1)-bound):(i*bound),])
  }
  return(list)
}

Ejemplo:

x <- matrix(c(1:10), ncol=1)
x
# [,1]
# [1,]    1
# [2,]    2
# [3,]    3
# [4,]    4
# [5,]    5
# [6,]    6
# [7,]    7
# [8,]    8
# [9,]    9
#[10,]   10

x.split <- df_split(x,5)
x.split
# [[1]]
# [1] 1 2

# [[2]]
# [1] 3 4

# [[3]]
# [1] 5 6

# [[4]]
# [1] 7 8

# [[5]]
# [1] 9 10
Yohan Obadia
fuente
2

El uso del paquete caTools en el código de muestra R será el siguiente: -

data
split = sample.split(data$DependentcoloumnName, SplitRatio = 0.6)
training_set = subset(data, split == TRUE)
test_set = subset(data, split == FALSE)
Yash Sharma
fuente
2

Use la función base R. runifgenera valores distribuidos uniformemente de 0 a 1. Al variar el valor de corte (train.size en el ejemplo a continuación), siempre tendrá aproximadamente el mismo porcentaje de registros aleatorios por debajo del valor de corte.

data(mtcars)
set.seed(123)

#desired proportion of records in training set
train.size<-.7
#true/false vector of values above/below the cutoff above
train.ind<-runif(nrow(mtcars))<train.size

#train
train.df<-mtcars[train.ind,]


#test
test.df<-mtcars[!train.ind,]
Konstantin Mingoulin
fuente
Esta sería una respuesta mucho mejor si mostrara un par de líneas adicionales para crear realmente los conjuntos de entrenamiento y prueba (con los que los novatos a menudo luchan).
Gregor Thomas el
2

Suponiendo que df es su marco de datos, y que desea crear 75% de entrenamiento y 25% de prueba

all <- 1:nrow(df)
train_i <- sort(sample(all, round(nrow(df)*0.75,digits = 0),replace=FALSE))
test_i <- all[-train_i]

Luego para crear un tren y probar marcos de datos

df_train <- df[train_i,]
df_test <- df[test_i,]
Corentin
fuente
1
require(caTools)

set.seed(101)            #This is used to create same samples everytime

split1=sample.split(data$anycol,SplitRatio=2/3)

train=subset(data,split1==TRUE)

test=subset(data,split1==FALSE)

La sample.split()función agregará una columna adicional 'split1' al marco de datos y 2/3 de las filas tendrán este valor como TRUE y otras como FALSE. Ahora las filas donde split1 es TRUE se copiarán en el tren y otras filas se copiarán para probar marco de datos.

Abhishek
fuente
1

Me topé con este, también puede ayudar.

set.seed(12)
data = Sonar[sample(nrow(Sonar)),]#reshufles the data
bound = floor(0.7 * nrow(data))
df_train = data[1:bound,]
df_test = data[(bound+1):nrow(data),]
usuario322203
fuente
1

Podemos dividir los datos en una proporción particular aquí, es 80% de entrenamiento y 20% en un conjunto de datos de prueba.

ind <- sample(2, nrow(dataName), replace = T, prob = c(0.8,0.2))
train <- dataName[ind==1, ]
test <- dataName[ind==2, ]
Adarsh ​​Pawar
fuente
0

Tenga cuidado samplecon la división si busca resultados reproducibles. Si sus datos cambian aunque sea ligeramente, la división variará incluso si la usa set.seed. Por ejemplo, imagine que la lista ordenada de ID en sus datos es todos los números entre 1 y 10. Si acaba de dejar una observación, digamos 4, el muestreo por ubicación produciría resultados diferentes porque ahora 5 a 10 todos los lugares movidos.

Un método alternativo es usar una función hash para asignar ID a algunos números pseudoaleatorios y luego muestrear el mod de estos números. Esta muestra es más estable porque la asignación ahora está determinada por el hash de cada observación, y no por su posición relativa.

Por ejemplo:

require(openssl)  # for md5
require(data.table)  # for the demo data

set.seed(1)  # this won't help `sample`

population <- as.character(1e5:(1e6-1))  # some made up ID names

N <- 1e4  # sample size

sample1 <- data.table(id = sort(sample(population, N)))  # randomly sample N ids
sample2 <- sample1[-sample(N, 1)]  # randomly drop one observation from sample1

# samples are all but identical
sample1
sample2
nrow(merge(sample1, sample2))

[1] 9999

# row splitting yields very different test sets, even though we've set the seed
test <- sample(N-1, N/2, replace = F)

test1 <- sample1[test, .(id)]
test2 <- sample2[test, .(id)]
nrow(test1)

[1] 5000

nrow(merge(test1, test2))

[1] 2653

# to fix that, we can use some hash function to sample on the last digit

md5_bit_mod <- function(x, m = 2L) {
  # Inputs: 
  #  x: a character vector of ids
  #  m: the modulo divisor (modify for split proportions other than 50:50)
  # Output: remainders from dividing the first digit of the md5 hash of x by m
  as.integer(as.hexmode(substr(openssl::md5(x), 1, 1)) %% m)
}

# hash splitting preserves the similarity, because the assignment of test/train 
# is determined by the hash of each obs., and not by its relative location in the data
# which may change 
test1a <- sample1[md5_bit_mod(id) == 0L, .(id)]
test2a <- sample2[md5_bit_mod(id) == 0L, .(id)]
nrow(merge(test1a, test2a))

[1] 5057

nrow(test1a)

[1] 5057

el tamaño de la muestra no es exactamente 5000 porque la asignación es probabilística, pero no debería ser un problema en muestras grandes gracias a la ley de los números grandes.

Ver también: http://blog.richardweiss.org/2016/12/25/hash-splits.html y /crypto/20742/statistical-properties-of-hash-functions-when -cálculo-módulo

dzeltzer
fuente
Agregado como una pregunta separada: stackoverflow.com/questions/52769681/…
dzeltzer
Quiero desarrollar el modelo auto.arima a partir de datos de series de tiempo múltiples y quiero usar 1 año de datos, 3 años de datos, 5, 7 ... en un intervalo de dos años de cada serie para construir el modelo y probarlo en El conjunto de pruebas restante. ¿Cómo hago el subconjunto para que el modelo ajustado tenga lo que quiero? Agradezco su ayuda
Stackuser
0
set.seed(123)
llwork<-sample(1:length(mydata),round(0.75*length(mydata),digits=0)) 
wmydata<-mydata[llwork, ]
tmydata<-mydata[-llwork, ]
Xavier Jiménez Albán
fuente
-2

Hay una manera muy simple de seleccionar varias filas usando el índice R para filas y columnas. Esto le permite dividir LIMPIA el conjunto de datos dado un número de filas, digamos el primer 80% de sus datos.

En R, todas las filas y columnas están indexadas, por lo que DataSetName [1,1] es el valor asignado a la primera columna y la primera fila de "DataSetName". Puedo seleccionar filas usando [x,] y columnas usando [, x]

Por ejemplo: si tengo un conjunto de datos convenientemente llamado "datos" con 100 filas, puedo ver las primeras 80 filas usando

Vista (datos [1:80,])

De la misma manera, puedo seleccionar estas filas y subconjunto usando:

tren = datos [1:80,]

prueba = datos [81: 100,]

Ahora tengo mis datos divididos en dos partes sin posibilidad de remuestreo. Rapido y Facil.

Dan Butorovich
fuente
1
Si bien es cierto que los datos se pueden dividir de esa manera, no se recomienda. Algunos conjuntos de datos están ordenados por una variable que desconoce. Por lo tanto, es mejor probar qué filas se considerarán como entrenamiento en lugar de tomar las primeras n filas.
user5029763
1
Si baraja los datos antes de separarlos para el conjunto de prueba y entrenamiento, su sugerencia funciona.
Hadij