I'm using R to do machine learning. Following standard machine learning methodology, I would like to randomly split my data into training, validation, and test data sets. How do I do that in R?
I know there are some related questions on how to split into 2 data sets (e.g. this post), but it is not obvious how to do it for 3 split data sets. By the way, the correct approach is to use 3 data sets (including a validation set to tune your hyperparameters).
Split the dataset We can use the train_test_split to first make the split on the original dataset. Then, to get the validation set, we can apply the same function to the train set to get the validation set. In the function below, the test set size is the ratio of the original data we want to use as the test set.
Use the split() function in R to split a vector or data frame. Use the unsplit() method to retrieve the split vector or data frame.
This linked approach for two groups (using floor
) doesn't extend naturally to three. I'd do
spec = c(train = .6, test = .2, validate = .2) g = sample(cut( seq(nrow(df)), nrow(df)*cumsum(c(0,spec)), labels = names(spec) )) res = split(df, g)
To check the results:
sapply(res, nrow)/nrow(df) # train test validate # 0.59375 0.18750 0.21875 # or... addmargins(prop.table(table(g))) # train test validate Sum # 0.59375 0.18750 0.21875 1.00000
With set.seed(1)
run just before, the result looks like
$train mpg cyl disp hp drat wt qsec vs am gear carb Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4 Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4 Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3 Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3 Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3 Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2 AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2 Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2 Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1 Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2 $test mpg cyl disp hp drat wt qsec vs am gear carb Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4 Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4 Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4 Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6 $validate mpg cyl disp hp drat wt qsec vs am gear carb Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4 Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4 Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2 Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
Data.frames can be accessed like res$test
or res[["test"]]
.
cut
is the standard tool for partitioning based on shares.
Following the approach shown in this post, here is working R code to divide a dataframe into three new dataframes for testing, validation, and test. The three subsets are non-overlapping.
# Create random training, validation, and test sets # Set some input variables to define the splitting. # Input 1. The data frame that you want to split into training, validation, and test. df <- mtcars # Input 2. Set the fractions of the dataframe you want to split into training, # validation, and test. fractionTraining <- 0.60 fractionValidation <- 0.20 fractionTest <- 0.20 # Compute sample sizes. sampleSizeTraining <- floor(fractionTraining * nrow(df)) sampleSizeValidation <- floor(fractionValidation * nrow(df)) sampleSizeTest <- floor(fractionTest * nrow(df)) # Create the randomly-sampled indices for the dataframe. Use setdiff() to # avoid overlapping subsets of indices. indicesTraining <- sort(sample(seq_len(nrow(df)), size=sampleSizeTraining)) indicesNotTraining <- setdiff(seq_len(nrow(df)), indicesTraining) indicesValidation <- sort(sample(indicesNotTraining, size=sampleSizeValidation)) indicesTest <- setdiff(indicesNotTraining, indicesValidation) # Finally, output the three dataframes for training, validation and test. dfTraining <- df[indicesTraining, ] dfValidation <- df[indicesValidation, ] dfTest <- df[indicesTest, ]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With