# How to split train/test data 50% by class and grouping by Object ID in R?

I get pixel values ​​from it using reference polygons. Extracted pixel values are in data frame, but one row represent extracted values for single pixel. In the classification I need to split the dataset into test (50%) and training (50%) by class (tree, meadow e.t.c)

I know how to split a set according to classes. However, I want values ​​extracted for one polygon to be assigned to one of the sets (training OR test ) and they were not mixed

For this purpose I want to use the polygon ID (Object Identification). I would like to do this using the createDataPartition function. These are just two sample classes (there are many more)

Here is part of table with extracted values:

"band_1"    "band_2"    "band_3"    "CLASS" "Id"
110 134 119 "tree"  1
112 133 118 "tree"  1
105 125 110 "tree"  2
112 132 117 "tree"  2


Here is code:

trainIndeks <- caret::createDataPartition(EXTRACTED$CLASS, p = 0.5, list=FALSE, times = 1) dataTrain <- EXTRACTED[trainIndeks,] dataTest <- EXTRACTED[-trainIndeks,]  • However, I do not want to split fields with the same ID (I want a class with the same ID to be in training or test set and not not be splited) - that's exactly what train/test splitting does. Could you please be more specific? What does ID mean in your data set? – Piotr Rarus - Reinstate Monica Dec 13 '19 at 14:05 • I corrected the question. – Nicolas Dec 13 '19 at 15:56 ## 1 Answer Instead of: dataTrain <- EXTRACTED[trainIndeks,] dataTest <- EXTRACTED[-trainIndeks,]  try: dataTrain <- EXTRACTED[ID %% 2 == 1,] dataTest <- EXTRACTED[ID %% 2 == 0,]  dataTrain will contain only odd ID, dataTest only even ones. Using this method you may lose the balance of CLASS distribution between dataTrain and dataTest, but you may improve it by replication or removing of a few records, or by checking the distribution in other splitting, e.g. dataTrain <- EXTRACTED[ID %% 4 < 2,] dataTest <- EXTRACTED[ID %% 4 > 1,]  EDIT: For random changing the split, you can use: set.seed(123) N <- 10 #N <- round(max(EXTRACTED$ID)/10) # for more random grouping
p <- 0.5 # train/(train+test) ratio
idx <- sample(0:(N-1),round(N*p))
dataTrain <- EXTRACTED[ID %% N %in% idx,]
dataTest  <- EXTRACTED[!(ID %% N %in% idx),]

• That's not exactly what I mean. I corrected the question – Nicolas Dec 13 '19 at 15:58
• Hm, the previous version of the question and the top of train/test datasets needed (and not mentioned aim - to avoid data leakage) were much clear for me. My solution should be good enough if the number of unique ID is over 20 times higher than the number of unique CLASS - I often use it in similar situations. – Grzegorz Sionkowski Dec 13 '19 at 18:06
• I checked and your method works, thank you. Will test on a larger collection and let you know. Could you explain why ,, if the number of unique ID is over 20 times higher than the number of unique CLASS ''? – Nicolas Dec 13 '19 at 18:24
• Number 2 is not acceptable in your case because of specific distribution (pure one CLASS in each ID), 200 would be safe in any case, 20 is in between ;) – Grzegorz Sionkowski Dec 13 '19 at 19:16
• Thank you, I have one more question: To better assess the accuracy of the classifier, I use it in a loop, but I don't know how to randomly change the data so that it doesn't always get to the same set (test or training) and goes randomly to the test or training. – Nicolas Dec 15 '19 at 9:19