Como dividir dados em conjuntos de treinamento / teste usando a função de amostra

160

Acabei de começar a usar o R ​​e não sei como incorporar meu conjunto de dados com o seguinte código de exemplo:

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

Eu tenho um conjunto de dados que preciso colocar em um conjunto de treinamento (75%) e teste (25%). Não tenho certeza de quais informações devo colocar no tamanho x? X é o arquivo do conjunto de dados e tamanho quantas amostras tenho?

Susie Humby
fonte
1
xpode ser o índice (linha / coluna, digamos) do seu data. sizepode ser 0.75*nrow(data). Tente sample(1:10, 4, replace = FALSE, prob = NULL)ver o que faz.
harkmug

Respostas:

255

Existem inúmeras abordagens para obter o particionamento de dados. Para uma abordagem mais completa, dê uma olhada na createDataPartitionfunção no caToolspacote.

Aqui está um exemplo simples:

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
fonte
Estou um pouco confuso o que garante que esse código retorne um teste único e treine o df? Parece funcionar, não me interpretem mal. Apenas tendo problemas para entender como subtrair os índices leva a observações únicas. Por exemplo, se você tivesse um df com 10 linhas e uma coluna, e a coluna contivesse 1,2,3,4,5,6,7,8,9,10 e você seguisse esse código, o que impede um trem de ter índice 4 e teste com -6 -> 10 - 6 = 4 também?
goldisfine 5/05
1
obrigado. Eu tentei mtcars[!train_ind]e, embora não tenha falhado, não funcionou como esperado. Como eu poderia definir um subconjunto usando o !?
user989762
@ user989762 !são usados ​​para TRUE/FALSEíndices lógicos ( ) e não. Se você deseja usar um subconjunto !, tente algo como mtcars [ !seq_len(nrow(mtcars)) %in% train_ind,] (não testado).
dickoa
1
@VedaadShakib quando você usa "-" omite todo o índice em train_ind dos seus dados. Dê uma olhada em adv-r.had.co.nz/Subsetting.html . Espero que ajude
dickoa
1
Não está createDataPartitiondentro carete não caTools?
J. Mini
93

Isso pode ser feito facilmente por:

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, ]

Usando o pacote caTools :

require(caTools)
set.seed(101) 
sample = sample.split(data$anycolumn, SplitRatio = .75)
train = subset(data, sample == TRUE)
test  = subset(data, sample == FALSE)
TheMI
fonte
4
Recentemente, fiz um curso com o MIT e eles usaram a abordagem usando caTools por toda parte. Obrigado
Chetan Sharma
1
sample = sample.split(data[,1], SplitRatio = .75)Deve remover a necessidade de nomear uma coluna.
Benjamin Ziepert
33

Eu usaria dplyrpara isso, torna super simples. Requer uma variável de ID no seu conjunto de dados, o que é uma boa ideia, não apenas para a criação de conjuntos, mas também para a rastreabilidade durante o seu projeto. Adicione-o se ainda não o contiver.

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

É quase o mesmo código, mas com uma aparência mais agradável

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
fonte
Sim! Nice look!
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
fonte
3
Embora uma resposta apenas de código seja uma resposta, é melhor fornecer algumas explicações.
C8H10N4O2
o que é m_train? Eu acho que você quis dizer, sub-treinar o data.frame original. Portanto, o código revisado deve estar treinando <-sub_train [intrain] e testando <-sub_train [-intrain,]. Gostaria de saber por que ninguém foi capaz de identificar esse grande problema com sua resposta nos últimos cinco anos!
mnm
21

Vou dividir 'a' no trem (70%) e testar (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,]

feito

hyunwoo jeong
fonte
4
você precisa importar o pacote dpyr, require (dplyr)
TheMI
Essa resposta me ajudou, mas eu precisava ajustá-la para obter os resultados esperados. Como é, o conjunto de dados 'train' possui nomes de nomes = sid de números inteiros seqüenciais: 1,2,3,4, ... enquanto você deseja que sid seja o número de proprietários do conjunto de dados original 'a', que desde que selecionados aleatoriamente sejam os números inteiros sequenciais. Portanto, é necessário criar a variável id em 'a' primeiro.
21716 Scott Murff #
row.names (mtcars) <- NULL; train <-dplyr :: sample_frac (mtcars, 0,5); teste <-mtcars [-as.numeric (row.names (train)),] # Fiz isso com meus dados, o código original não funcionará se os nomes de suas linhas já estiverem definidos como números
Christopher John
16

Minha solução é basicamente a mesma que a de dickoa, mas um pouco mais 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
fonte
Qual é a variável suíço?
billmccord
7

Apenas uma maneira mais breve e simples usando a incrível 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
fonte
1
Você queria usar Default[-train_index,]para a última linha.
Matt L.
5

Se você digitar:

?sample

Se abrirá um menu de ajuda para explicar o que significam os parâmetros da função de amostra.

Eu não sou um especialista, mas aqui está um código que tenho:

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

Isso lhe dará 75% de treinamento e 25% de teste.

user2502836
fonte
5

Depois de examinar todos os diferentes métodos publicados aqui, não vi ninguém utilizar TRUE/FALSEpara selecionar e desmarcar dados. Então, pensei em compartilhar um método utilizando essa 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, ]

Explicação

Existem várias maneiras de selecionar dados de R, geralmente as pessoas usam índices positivos / negativos para selecionar / desmarcar respectivamente. No entanto, as mesmas funcionalidades podem ser alcançadas usandoTRUE/FALSE para selecionar / desmarcar.

Considere o seguinte exemplo.

# 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
fonte
4

Minha solução embaralha as linhas e pega os primeiros 75% das linhas como trem e os últimos 25% como teste. Super 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
fonte
4

Eu posso sugerir o uso do pacote 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)

fonte
3

scorecard pacote tem uma função útil para isso, onde você pode especificar a proporção e a semente

library(scorecard)

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

Os dados de teste e trem são armazenados em uma lista e podem ser acessados ​​chamando dt_list$trainedt_list$test

camnesia
fonte
2

Abaixo de uma função que cria uma listsubamostra do mesmo tamanho que não é exatamente o que você deseja, mas pode ser útil para outras pessoas. No meu caso, para criar várias árvores de classificação em amostras menores para testar o overfitting:

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

Exemplo:

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
fonte
2

O uso do pacote caTools no código de exemplo R será o seguinte: -

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

Use a base R. A função runifgera valores uniformemente distribuídos de 0 a 1. Por variando o valor de corte (train.size no exemplo abaixo), você sempre terá aproximadamente a mesma porcentagem de registros aleatórios abaixo do 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
fonte
Essa seria uma resposta muito melhor se ela mostrasse algumas linhas extras para realmente criar os conjuntos de treinamento e teste (com os quais os novatos geralmente lutam).
Gregor Thomas
2

Supondo que df seja seu quadro de dados e que você queira criar 75% de treinamento e 25% de teste

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

Em seguida, crie um trem e teste os quadros de dados

df_train <- df[train_i,]
df_test <- df[test_i,]
Corentin
fonte
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)

A sample.split()função adicionará uma coluna extra 'split1' ao quadro de dados e 2/3 das linhas terão esse valor como TRUE e outros como FALSE. Agora, as linhas em que split1 é TRUE serão copiadas no trem e outras linhas serão copiadas para teste. quadro de dados.

Abhishek
fonte
1

Encontrei este aqui, também pode ajudar.

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),]
user322203
fonte
1

Podemos dividir os dados em uma proporção específica, pois são 80% de trem e 20% em um conjunto de dados de teste.

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

Cuidado samplepara dividir se você procura resultados reproduzíveis. Se seus dados mudarem um pouco, a divisão variará mesmo que você use set.seed. Por exemplo, imagine que a lista ordenada de IDs em seus dados seja todos os números entre 1 e 10. Se você acabou de fazer uma observação, digamos 4, a amostragem por local produziria resultados diferentes, porque agora 5 a 10 todos os locais foram movidos.

Um método alternativo é usar uma função hash para mapear IDs em alguns números pseudo-aleatórios e, em seguida, fazer uma amostra no mod desses números. Essa amostra é mais estável porque a atribuição agora é determinada pelo hash de cada observação e não por sua posição relativa.

Por exemplo:

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

O tamanho da amostra não é exatamente 5000, porque a atribuição é probabilística, mas não deve ser um problema em amostras grandes, graças à lei de grandes números.

Consulte também: http://blog.richardweiss.org/2016/12/25/hash-splits.html e /crypto/20742/statistical-properties-of-hash-functions-when -calculating-module

dzeltzer
fonte
Adicionado como uma pergunta separada: stackoverflow.com/questions/52769681/…
dzeltzer 11/11
Desejo desenvolver o modelo auto.arima a partir de vários dados de séries temporais e quero usar 1 ano de dados, 3 anos de dados, 5, 7 ... em um intervalo de dois anos de cada série para construir o modelo e testá-lo em o conjunto de testes restante. Como faço a subconjunto para que o modelo ajustado tenha o que eu quero? Agradeço a sua ajuda
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
fonte
-2

Existe uma maneira muito simples de selecionar um número de linhas usando o índice R para linhas e colunas. Isso permite que você divida LIMPEZA o conjunto de dados, com um número de linhas - digamos, o primeiro 80% dos seus dados.

Em R, todas as linhas e colunas são indexadas para que DataSetName [1,1] seja o valor atribuído à primeira coluna e à primeira linha de "DataSetName". Posso selecionar linhas usando [x,] e colunas usando [, x]

Por exemplo: Se eu tiver um conjunto de dados convenientemente chamado de "dados" com 100 linhas, posso visualizar as primeiras 80 linhas usando

Visualização (dados [1:80,])

Da mesma maneira, posso selecionar essas linhas e subconjuntá-las usando:

train = data [1:80,]

teste = dados [81: 100,]

Agora, meus dados estão divididos em duas partes, sem a possibilidade de reamostragem. Rápido e fácil.

Dan Butorovich
fonte
1
Embora seja verdade que os dados podem ser divididos dessa maneira, isso não é aconselhável. Alguns conjuntos de dados são ordenados por uma variável que você não conhece. Portanto, é melhor provar quais linhas serão consideradas como treinamento em vez de ocupar as primeiras n linhas.
User5029763
1
Se você embaralhar os dados antes de separá-los para o conjunto de testes e treinamento, sua sugestão funcionará.
23419 Hadij