有没有办法在每个样本中划分具有相同比例的分类值的数据集?

Is there a way to divide a dataset having the same proportion of a categorical value in each sample?

我是 R 的新手,但我有一个问题。我有一个数据集(长度为 1593 obs),其中包括一个内部有多个字符串的字符类型变量和一个对应于每个字符串的具有 2 个级别 -0 和 1- 的因子变量。为了创建分类,我想将该数据集的 75% 作为测试样本,25% 作为训练样本,但我还希望在测试样本和训练样本中具有相同比例的 0。有什么方法可以做到这一点?

这是我的数据集的结构

data.frame':    1593 obs. of  6 variables:
 $ match_id: int  0 0 0 0 0 0 0 0 0 0 ...
 $ Binary  : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 2 ...
 $ key     : chr  "force it" "space created" "hah" "ez 500" ...

注意:我实际上是在遵循 Brett Lantz 撰写的“使用 R 进行机器学习”一书中的代码,并将它们应用到我的数据集。我想在我的数据集中实现的部分是书中的这一部分:

To confirm that the subsets are representative of the complete set of SMS data, let's
compare the proportion of spam in the training and test data frames:
> prop.table(table(sms_raw_train$type))
ham        spam
0.8647158 0.1352842
> prop.table(table(sms_raw_test$type))
ham         spam
0.8683453 0.1316547
Both the training data and test data contain about 13 percent spam. This suggests
that the spam messages were divided evenly between the two datasets.

感谢您的帮助

如果您不想打乱数据并将每组的前 75% 作为训练,您可以做一些简单的事情,例如

data <- data %>%
  group_by(Binary) %>%
  mutate(is_train = row_number() <= 0.75 * n()) %>%
  ungroup()

如果要打乱数据,只需使用 sample.int(n()) 而不是 row_number()

一旦你在那里有了标志,你就可以轻松地从训练和测试集中过滤数据。

train_data <- filter(data, is_train)
test_data <- filter(data, !is_train)

caret 包中的 createDataPartition() 函数通常用于此目的,例如

library(caret)
set.seed(300)
trainIndex <- createDataPartition(iris$Species, p = .75, 
                                  list = FALSE, 
                                  times = 1)
irisTrain <- iris[ trainIndex,]
irisTest  <- iris[-trainIndex,]

str(irisTrain)
>'data.frame':  114 obs. of  5 variables:
> $ Sepal.Length: num  5.1 4.9 4.7 5 5.4 4.6 5 4.4 5.4 4.8 ...
> $ Sepal.Width : num  3.5 3 3.2 3.6 3.9 3.4 3.4 2.9 3.7 3.4 ...
> $ Petal.Length: num  1.4 1.4 1.3 1.4 1.7 1.4 1.5 1.4 1.5 1.6 ...
> $ Petal.Width : num  0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.2 0.2 ...
> $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 >...

str(irisTest)
>'data.frame':  36 obs. of  5 variables:
> $ Sepal.Length: num  4.6 4.9 5.1 5.1 4.6 4.8 5.2 5.5 5.5 5.1 ...
> $ Sepal.Width : num  3.1 3.1 3.5 3.8 3.6 3.1 4.1 4.2 3.5 3.8 ...
> $ Petal.Length: num  1.5 1.5 1.4 1.5 1 1.6 1.5 1.4 1.3 1.9 ...
> $ Petal.Width : num  0.2 0.1 0.3 0.3 0.2 0.2 0.1 0.2 0.2 0.4 ...
> $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 >...

prop.table(table(irisTrain$Species))
>    setosa versicolor  virginica 
> 0.3333333  0.3333333  0.3333333 

prop.table(table(irisTest$Species))
>   setosa versicolor  virginica 
> 0.3333333  0.3333333  0.3333333 

这提供了一个伪随机~分层抽样到训练和测试队列中,这就是我在自己的工作中使用的。