Come dividere i dati in set di addestramento / test usando la funzione di esempio


160

Ho appena iniziato a usare R e non sono sicuro di come integrare il mio set di dati con il seguente codice di esempio:

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

Ho un set di dati che devo inserire in un set di formazione (75%) e test (25%). Non sono sicuro di quali informazioni dovrei inserire nella dimensione x? X è il file del set di dati e dimensioni quanti campioni ho?


1
xpuò essere l'indice (riga / riga nn. dire) del tuo data. sizepuò essere 0.75*nrow(data). Prova sample(1:10, 4, replace = FALSE, prob = NULL)a vedere cosa fa.
Harkmug,

Risposte:


255

Esistono numerosi approcci per ottenere il partizionamento dei dati. Per un approccio più completo dai un'occhiata alla createDataPartitionfunzione incaTools pacchetto.

Qui c'è un semplice esempio:

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

Sono un po 'confuso ciò che garantisce questo codice restituisce un test univoco e si allena df? Sembra funzionare, non fraintendetemi. Basta avere difficoltà a capire come la sottrazione degli indici porta a osservazioni uniche. Ad esempio, se avevi un df con 10 righe e una colonna e una colonna conteneva 1,2,3,4,5,6,7,8,9,10 e hai seguito questo codice, ciò che impedisce a un treno di avere indice 4 e test con -6 -> 10 - 6 = 4 pure?
goldisfine

1
grazie. Ho provato mtcars[!train_ind]e anche se non ha fallito, non ha funzionato come previsto. Come posso effettuare il sottoinsieme usando il !?
user989762

@ user989762 !sono usati per gli TRUE/FALSEindici logici ( ) e non. Se si desidera eseguire il sottoinsieme utilizzando !, provare qualcosa come mtcars [ !seq_len(nrow(mtcars)) %in% train_ind,] (non testato).
dickoa,

1
@VedaadShakib quando usi "-" omette tutto l'indice in train_ind dai tuoi dati. Dai un'occhiata a adv-r.had.co.nz/Subsetting.html . Spero che sia d'aiuto
dickoa,

1
Non è createDataPartitiondentro carete no caTools?
J. Mini

93

Può essere facilmente fatto da:

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

Utilizzando il pacchetto caTools :

require(caTools)
set.seed(101) 
sample = sample.split(data$anycolumn, SplitRatio = .75)
train = subset(data, sample == TRUE)
test  = subset(data, sample == FALSE)

4
Recentemente ho fatto un corso con il MIT e hanno usato l'approccio usando caTools dappertutto. Grazie
Chetan Sharma,

1
sample = sample.split(data[,1], SplitRatio = .75)Dovrebbe rimuovere la necessità di nominare una colonna.
Benjamin Ziepert,

33

Userei dplyrper questo, lo rende super semplice. Richiede una variabile id nel set di dati, che è comunque una buona idea, non solo per la creazione di set, ma anche per la tracciabilità durante il progetto. Aggiungilo se non contiene già.

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

28

Questo è quasi lo stesso codice, ma in un aspetto più bello

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

Sì! Bell'aspetto!
Meenakshi

23
library(caret)
intrain<-createDataPartition(y=sub_train$classe,p=0.7,list=FALSE)
training<-m_train[intrain,]
testing<-m_train[-intrain,]

3
Mentre una risposta di solo codice è una risposta, è meglio fornire alcune spiegazioni.
C8H10N4O2,

che cos'è m_train? Penso che volevi dire, sub_train l'originale data.frame. Pertanto, il codice rivisto dovrebbe addestrare <-sub_train [intrain,] e testare <-sub_train [-intrain,]. Mi chiedo perché nessuno sia stato in grado di individuare questo grave problema con la tua risposta negli ultimi cinque anni!
mnm,

21

Dividerò "a" in treno (70%) e testerò (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,]

fatto


4
devi importare il pacchetto dpyr, richiedi (dplyr)
TheMI

Questa risposta mi ha aiutato, ma ho dovuto modificarla per ottenere i risultati previsti. Così com'è, il set di dati 'train' ha rownames = sid di numeri interi sequenziali: 1,2,3,4, ... mentre vuoi che sid sia il rownumbers del set di dati originale 'a', che dal momento che sono stati scelti casualmente ha vinto sono gli interi sequenziali. Quindi, è necessario prima creare la variabile id su 'a'.
Scott Murff,

row.names (mtcars) <- NULL; train <-dplyr :: sample_frac (mtcars, 0,5); test <-mtcars [-as.numeric (row.names (train)),] # Ho fatto questo con i miei dati, il codice originale non funziona se i nomi delle tue righe sono già impostati su numeri
Christopher John

16

La mia soluzione è sostanzialmente la stessa di Dickoa ma un po 'più facile da interpretare:

data(mtcars)
n = nrow(mtcars)
trainIndex = sample(1:n, size = round(0.7*n), replace=FALSE)
train = mtcars[trainIndex ,]
test = mtcars[-trainIndex ,]

Qual è la variabile svizzera?
billmccord,

7

Solo un modo più breve e semplice usando la fantastica libreria 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, ]

1
Intendevi usare Default[-train_index,]per l'ultima riga.
Matt L.

5

Se digiti:

?sample

Se avvierà un menu di aiuto per spiegare cosa significano i parametri della funzione di esempio.

Non sono un esperto, ma ecco un codice che ho:

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

Questo ti darà il 75% di treno e il 25% di prova.


5

Dopo aver esaminato tutti i diversi metodi pubblicati qui, non ho visto nessuno utilizzare TRUE/FALSEper selezionare e deselezionare i dati. Quindi ho pensato di condividere un metodo utilizzando quella tecnica.

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

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

Spiegazione

Esistono diversi modi per selezionare i dati da R, più comunemente le persone usano indici positivi / negativi per selezionare / deselezionare rispettivamente. Tuttavia, è possibile ottenere le stesse funzionalità utilizzandoTRUE/FALSE per selezionare / deselezionare.

Considera il seguente esempio.

# 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

4

La mia soluzione mescola le file, quindi prende il primo 75% delle file come treno e l'ultimo 25% come test. Super semplici!

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

4

Posso suggerire di usare il pacchetto 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)

3

scorecard il pacchetto ha una funzione utile per questo, dove è possibile specificare il rapporto e il seme

library(scorecard)

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

I dati del test e del treno sono memorizzati in un elenco e sono accessibili chiamando dt_list$trainedt_list$test


2

Di seguito una funzione che crea un listsottocampione della stessa dimensione che non è esattamente quello che volevi, ma potrebbe rivelarsi utile per gli altri. Nel mio caso per creare più alberi di classificazione su campioni più piccoli per testare il 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)
}

Esempio :

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

2

Utilizzare il pacchetto caTools nel codice di esempio R sarà il seguente: -

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

2

Usa la base R. La funzione runifgenera valori distribuiti uniformemente da 0 a 1. Variando il valore di cutoff (train.size nell'esempio seguente), avrai sempre approssimativamente la stessa percentuale di record casuali al di sotto del valore di cutoff.

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

Questa sarebbe una risposta molto migliore se mostrasse le linee extra di coppia per creare effettivamente i set di allenamento e test (con cui i neofiti spesso lottano).
Gregor Thomas,

2

Supponendo che df sia il tuo frame di dati e che desideri creare il 75% di training e il 25% di test

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

Quindi per creare un treno e testare i frame di dati

df_train <- df[train_i,]
df_test <- df[test_i,]

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()funzione aggiungerà una colonna aggiuntiva 'split1' al frame di dati e 2/3 delle righe avranno questo valore come TRUE e altre come FALSE. Ora le righe in cui split1 è TRUE verranno copiate nel treno e altre righe verranno copiate per testare dataframe.


1

Mi sono imbattuto in questo, può anche aiutare.

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

1

Possiamo dividere i dati in un particolare rapporto qui è l'80% del treno e il 20% in un set di dati di prova.

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

0

Fai attenzione samplealla divisione se cerchi risultati riproducibili. Se i tuoi dati cambiano anche leggermente, la divisione varierà anche se lo usi set.seed. Ad esempio, immagina che l'elenco ordinato di ID nei tuoi dati contenga tutti i numeri tra 1 e 10. Se hai appena lasciato cadere un'osservazione, diciamo 4, il campionamento per posizione produrrebbe risultati diversi perché ora da 5 a 10 tutti i luoghi spostati.

Un metodo alternativo consiste nell'utilizzare una funzione hash per mappare gli ID in alcuni numeri pseudo casuali e quindi campionare sulla mod di questi numeri. Questo esempio è più stabile perché l'assegnazione è ora determinata dall'hash di ogni osservazione e non dalla sua posizione relativa.

Per esempio:

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

la dimensione del campione non è esattamente 5000 perché l'assegnazione è probabilistica, ma non dovrebbe essere un problema in grandi campioni grazie alla legge di grandi numeri.

Vedi anche: http://blog.richardweiss.org/2016/12/25/hash-splits.html e /crypto/20742/statistical-properties-of-hash-functions-when -calculating-modulo


Aggiunto come una questione separata: stackoverflow.com/questions/52769681/...
dzeltzer

Voglio sviluppare il modello auto.arima da più dati di serie temporali e voglio usare 1 anno di dati, 3 anni di dati, 5, 7 ... in un intervallo di due anni da ciascuna serie per costruire il modello e testarlo in il set di test rimanenti. Come posso effettuare il subsetting in modo che il modello montato abbia quello che voglio? Apprezzo il tuo aiuto
Stackuser

0
set.seed(123)
llwork<-sample(1:length(mydata),round(0.75*length(mydata),digits=0)) 
wmydata<-mydata[llwork, ]
tmydata<-mydata[-llwork, ]

-2

C'è un modo molto semplice per selezionare un numero di righe usando l'indice R per righe e colonne. Ciò consente di dividere in modo PULITO il set di dati in base a un numero di righe, ad esempio il 1 ° 80% dei dati.

In R tutte le righe e le colonne sono indicizzate, quindi DataSetName [1,1] è il valore assegnato alla prima colonna e alla prima riga di "DataSetName". Posso selezionare le righe usando [x,] e le colonne usando [, x]

Ad esempio: se ho un set di dati opportunamente chiamato "dati" con 100 righe, posso visualizzare le prime 80 righe usando

Vista (dati [1:80,])

Allo stesso modo, posso selezionare queste righe e sottoimpostarle usando:

train = data [1:80,]

test = data [81: 100,]

Ora ho i miei dati divisi in due parti senza possibilità di ricampionamento. Facile e veloce.


1
Sebbene sia vero che i dati possono essere suddivisi in questo modo, non è consigliabile. Alcuni set di dati sono ordinati in base a una variabile di cui non si è a conoscenza. Quindi è meglio campionare quali righe saranno considerate come training invece di prendere le prime n righe.
user5029763

1
Se mescoli i dati prima di separarli per il test e il set di addestramento, il tuo suggerimento funziona.
Hadij
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.