Comment diviser les données en ensembles d'entraînement / de test à l'aide de la fonction exemple


160

Je viens de commencer à utiliser R et je ne sais pas comment incorporer mon ensemble de données avec l'exemple de code suivant:

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

J'ai un ensemble de données que je dois mettre dans un ensemble de formation (75%) et de test (25%). Je ne sais pas quelles informations je suis censé mettre dans le x et la taille? X est-il le fichier de l'ensemble de données et taille combien d'échantillons j'ai?


1
xpeut être l'index (ligne / col nos. dire) de votre data. sizepeut être 0.75*nrow(data). Essayez sample(1:10, 4, replace = FALSE, prob = NULL)de voir ce qu'il fait.
harkmug

Réponses:


255

Il existe de nombreuses approches pour réaliser le partitionnement des données. Pour une approche plus complète, jetez un œil à la createDataPartitionfonction dans le caToolspackage.

Voici un exemple 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, ]

Je suis un peu confus ce qui garantit que ce code renvoie un test unique et forme df? Cela semble fonctionner, ne vous méprenez pas. Le simple fait d'avoir du mal à comprendre comment la soustraction des indices conduit à des observations uniques. Par exemple, si vous aviez un df avec 10 lignes et une colonne, et que la colonne contenait 1,2,3,4,5,6,7,8,9,10 et que vous suiviez ce code, ce qui empêche un train d'avoir index 4 et test ayant -6 -> 10 - 6 = 4 aussi?
goldisfine

1
remercier. J'ai essayé mtcars[!train_ind]et même si cela n'a pas échoué, cela n'a pas fonctionné comme prévu. Comment pourrais-je sous-ensemble utiliser le !?
user989762

@ user989762 !sont utilisés pour la logique ( TRUE/FALSE) et non pour les index. Si vous voulez utiliser un sous-ensemble !, essayez quelque chose comme mtcars [ !seq_len(nrow(mtcars)) %in% train_ind,] (non testé).
dickoa

1
@VedaadShakib lorsque vous utilisez "-", il omet tout l'index de train_ind de vos données. Jetez un œil à adv-r.had.co.nz/Subsetting.html . J'espère que ça aide
dickoa

1
Est -ce pas createDataPartitiondans caretet non caTools?
J. Mini

93

Cela peut être facilement fait par:

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

En utilisant le package caTools :

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

4
J'ai récemment suivi un cours avec le MIT et ils ont utilisé l'approche utilisant caTools partout. Merci
Chetan Sharma

1
sample = sample.split(data[,1], SplitRatio = .75)Devrait supprimer la nécessité de nommer une colonne.
Benjamin Ziepert le

33

J'utiliserais dplyrpour cela, c'est super simple. Il nécessite une variable id dans votre ensemble de données, ce qui est une bonne idée de toute façon, non seulement pour créer des ensembles, mais aussi pour la traçabilité pendant votre projet. Ajoutez-le s'il ne contient pas déjà.

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

28

C'est presque le même code, mais en plus beau look

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

Ouaip! Joli look!
MeenakshiSundharam

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

3
Bien qu'une réponse contenant uniquement un code soit une réponse, il est préférable de fournir des explications.
C8H10N4O2

qu'est-ce que m_train? Je pense que vous vouliez dire, sub_trainer le data.frame d'origine. Par conséquent, le code révisé devrait être training <-sub_train [intrain,] et testing <-sub_train [-intrain,]. Je me demande pourquoi personne n'a pu déceler ce problème majeur avec votre réponse au cours des cinq dernières années!
mnm

21

Je vais diviser 'a' en train (70%) et 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,]

terminé


4
vous devez importer le package dpyr, nécessite (dplyr)
TheMI

Cette réponse m'a aidé, mais j'ai eu besoin de la peaufiner pour obtenir les résultats escomptés. En l'état, le jeu de données 'train' a rownames = sid d'entiers séquentiels: 1,2,3,4, ... alors que vous voulez que sid soit les rownumber de l'ensemble de données original 'a', qui, puisqu'ils sont sélectionnés au hasard, ont gagné Ce ne sont pas les entiers séquentiels. Il est donc nécessaire de créer d'abord la variable id sur «a».
Scott Murff

row.names (mtcars) <- NULL; train <-dplyr :: sample_frac (mtcars, 0,5); test <-mtcars [-as.numeric (row.names (train)),] # J'ai fait ça à mes données, le code d'origine ne fonctionne pas si vos noms de lignes sont déjà définis sur des nombres
Christopher John

16

Ma solution est fondamentalement la même que celle de Dickoa mais un peu plus facile à interpréter:

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

Quelle est la variable swiss?
billmccord

7

Juste une manière plus brève et simple d'utiliser l'impressionnante bibliothèque de 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
Vouliez-vous utiliser Default[-train_index,]pour la dernière ligne.
Matt L.

5

Si vous tapez:

?sample

If lancera un menu d'aide pour expliquer ce que signifient les paramètres de la fonction exemple.

Je ne suis pas un expert, mais voici un code que j'ai:

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

Cela vous donnera 75% de train et 25% de test.


5

Après avoir parcouru toutes les différentes méthodes publiées ici, je n'ai vu personne utiliser TRUE/FALSEpour sélectionner et désélectionner des données. J'ai donc pensé partager une méthode utilisant cette technique.

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

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

Explication

Il existe plusieurs façons de sélectionner des données à partir de R, le plus souvent les gens utilisent des indices positifs / négatifs pour sélectionner / désélectionner respectivement. Cependant, les mêmes fonctionnalités peuvent être obtenues en utilisantTRUE/FALSE pour sélectionner / désélectionner.

Prenons l'exemple suivant.

# 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

Ma solution mélange les lignes, puis prend les premiers 75% des lignes comme train et les derniers 25% comme test. 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)),]

4

Je peux suggérer d'utiliser le package 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 package a une fonction utile pour cela, où vous pouvez spécifier le ratio et la graine

library(scorecard)

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

Les données de test et de train sont stockées dans une liste et sont accessibles en appelant dt_list$trainetdt_list$test


2

Ci-dessous une fonction qui crée un listdes sous-échantillons de la même taille qui n'est pas exactement ce que vous vouliez mais qui pourrait s'avérer utile pour d'autres. Dans mon cas, pour créer plusieurs arbres de classification sur des échantillons plus petits pour tester le surajustement:

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

Exemple :

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

Utiliser le package caTools dans l'exemple de code R sera le suivant: -

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

2

Utilisez la base R. La fonction runifgénère des valeurs uniformément réparties de 0 à 1. En variant la valeur de coupure (train.size dans l'exemple ci-dessous), vous aurez toujours approximativement le même pourcentage d'enregistrements aléatoires en dessous de la valeur de coupure.

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

Ce serait une bien meilleure réponse si elle montrait les deux lignes supplémentaires pour créer réellement les ensembles d'entraînement et de test (avec lesquels les débutants ont souvent du mal).
Gregor Thomas

2

En supposant que df est votre trame de données et que vous souhaitez créer 75% de train et 25% de test

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

Puis pour créer un train et tester des trames de données

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()fonction ajoutera une colonne supplémentaire 'split1' à dataframe et 2/3 des lignes auront cette valeur comme TRUE et d'autres comme FALSE.Maintenant les lignes où split1 est TRUE seront copiées dans train et les autres lignes seront copiées pour tester trame de données.


1

Je suis tombé sur celui-ci, cela peut aussi aider.

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

Nous pouvons diviser les données en un rapport particulier ici, il s'agit de 80% de train et de 20% dans un jeu de données de test.

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

0

Méfiez-vous du samplefractionnement si vous recherchez des résultats reproductibles. Si vos données changent même légèrement, la répartition variera même si vous utilisez set.seed. Par exemple, imaginez que la liste triée des identifiants dans vos données contient tous les nombres entre 1 et 10. Si vous venez de supprimer une observation, disons 4, l'échantillonnage par emplacement donnerait des résultats différents car maintenant 5 à 10 tous les lieux ont été déplacés.

Une méthode alternative consiste à utiliser une fonction de hachage pour mapper les identifiants en certains nombres pseudo aléatoires, puis à échantillonner sur le mod de ces nombres. Cet échantillon est plus stable car l'affectation est désormais déterminée par le hachage de chaque observation, et non par sa position relative.

Par exemple:

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] 5 000

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 taille de l'échantillon n'est pas exactement de 5000 car l'assignation est probabiliste, mais elle ne devrait pas poser de problème dans les grands échantillons grâce à la loi des grands nombres.

Voir également: http://blog.richardweiss.org/2016/12/25/hash-splits.html et /crypto/20742/statistical-properties-of-hash-functions-when -calculer-modulo


Ajouté en tant que question distincte: stackoverflow.com/questions/52769681/…
dzeltzer

Je souhaite développer le modèle auto.arima à partir de plusieurs séries de données chronologiques et je souhaite utiliser 1 an de données, 3 ans de données, 5, 7 ... dans un intervalle de deux ans de chaque série pour construire le modèle et le tester dans l'ensemble de test restant. Comment faire le sous-ensemble pour que le modèle ajusté ait ce que je veux? J'apprécie votre aide
Stackuser

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

-2

Il existe un moyen très simple de sélectionner un certain nombre de lignes à l'aide de l'index R pour les lignes et les colonnes. Cela vous permet de diviser proprement l'ensemble de données en fonction d'un certain nombre de lignes - disons les premiers 80% de vos données.

Dans R, toutes les lignes et colonnes sont indexées, donc DataSetName [1,1] est la valeur affectée à la première colonne et à la première ligne de "DataSetName". Je peux sélectionner des lignes en utilisant [x,] et des colonnes en utilisant [, x]

Par exemple: si j'ai un ensemble de données nommé "data" avec 100 lignes, je peux afficher les 80 premières lignes en utilisant

Afficher (données [1:80,])

De la même manière, je peux sélectionner ces lignes et les sous-ensembles en utilisant:

train = données [1:80,]

test = données [81: 100,]

Maintenant, mes données sont divisées en deux parties sans possibilité de rééchantillonnage. Rapide et facile.


1
Bien qu'il soit vrai que les données peuvent être divisées de cette façon, ce n'est pas conseillé. Certains ensembles de données sont classés par une variable dont vous n'avez pas connaissance. Il est donc préférable d'échantillonner les lignes qui seront considérées comme un entraînement au lieu de prendre les n premières lignes.
user5029763

1
Si vous mélangez les données avant de les séparer en jeu de test et d'apprentissage, votre suggestion fonctionne.
Hadij
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.