如何使用样本函数将数据分成训练集和测试集

201

我刚开始使用R,不确定如何将我的数据集与以下示例代码结合起来:

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

我有一个数据集,需要将其分为训练集(75%)和测试集(25%)。我不确定应该放入x和size的信息是什么?x是数据集文件吗?size是指样本数量吗?


1
x 可以是你的 data 的索引(行/列编号)。size 可以是 0.75*nrow(data)。尝试使用 sample(1:10, 4, replace = FALSE, prob = NULL) 查看它的作用。 - harkmug
28个回答

314

有许多方法可以实现数据分区。要了解更完整的方法,请查看caret包中的createDataPartition函数。

这里是一个简单的例子:

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

2
我有点困惑这段代码如何保证返回唯一的测试和训练数据框?它似乎可以工作,不要误解我的意思。只是我很难理解如何通过减去索引来得到唯一的观测值。例如,如果你有一个包含1,2,3,4,5,6,7,8,9,10的10行1列的数据框,并且你按照这个代码操作,那么什么阻止了训练数据具有索引4和测试数据具有-6 -> 10 - 6 = 4呢? - goldisfine
2
谢谢。我尝试了 mtcars[!train_ind],虽然它没有失败,但并没有按预期工作。我该如何使用 ! 进行子集操作? - user989762
2
@VedaadShakib 当你使用“-”时,它会从你的数据中省略train_ind的所有索引。请查看http://adv-r.had.co.nz/Subsetting.html。希望能帮到你。 - dickoa
5
"createDataPartition" 不是在 "caTools" 中而是在 "caret" 中吗? - J. Mini
1
我很确定这样做可以使得抽样结果保持一致。比如,如果你只是运行抽样操作,每次都会得到不同的样本,但是使用set.seed函数可以保持抽样结果的一致性。 - undefined
显示剩余10条评论

119

这可以很容易地完成:

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

通过使用caTools软件包:

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

6
最近我参加了一门由MIT开设的课程,他们在整个过程中都使用了caTools方法。谢谢。 - Chetan Sharma
2
sample = sample.split(data[,1], SplitRatio = .75) 应该可以避免给列命名的需要。 - Benjamin Ziepert
将向量Y中的数据按预定义比例分成2个箱子,同时保留Y中不同标签的相对[比率]。因此,如果这是一个分类问题,则第一个参数应该是包含要预测的类别的列。如果这是一个回归问题,最好像前面的解决方案一样使用内置的样本函数。 - Shri Samson

42

我会使用dplyr来完成这个任务,它使得整个过程非常简单。但是你需要在数据集中包含一个id变量,这个变量不仅可以用于创建数据集,还可以在项目跟踪中提高可追溯性。如果没有包含id变量,就需要添加。

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

31

这几乎是相同的代码,但外观更加美观。

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

是的!看起来不错! - MS Sankararaman
这个程序会随机选择数据吗?sample方法是内置的吗? - Regressor
是的,在步骤 df <- df[sample(nrow(df)), ] 中,所有行都是随机抽样的。请查看 https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/sample 以获取更多关于 R 基础函数 sample 的信息。 - Spacez

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

6
虽然提供仅有代码的回答是一种回答方式,但最好还是提供一些解释说明。 - C8H10N4O2
1
m_train是什么?我想你的意思是用sub_train替换原始数据框。因此,修改后的代码应该是training<-sub_train[intrain,]和testing<-sub_train[-intrain,]。我不知道为什么在过去的五年里没有人能够发现你答案中的这个重大问题! - mnm
OP没有明确要求分层... - Johannes Wiesner

22

我将把'a'数据集分成训练集(70%)和测试集(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,]

完成


4
你需要导入dplyr包,使用require(dplyr)。 - TheMI
这个答案对我很有帮助,但我需要调整一下才能得到预期的结果。 目前,数据集“train”的行名称为连续整数的sid:1,2,3,4, ...,而您想要的是sid成为原始数据集“a”的行号,由于它们是随机选择的,所以不会是连续整数。 因此,首先需要在“a”上创建id变量。 - Scott Murff
row.names(mtcars) <- NULL; train<-dplyr::sample_frac(mtcars, 0.5); test<-mtcars[-as.numeric(row.names(train)),] # 我对我的数据进行了这样的操作,如果你的行名称已经设置为数字,则原始代码将无法运行 - Christopher John
它看起来对我来说还好,但似乎不是随机选择。 - B_slash_

17

我的解决方案基本上与dickoa的相同,但更易于理解:

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

变量swiss是什么? - billmccord

16
我可以建议使用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)

值得强调的是,rsampletidymodels 框架的一部分,适用于使用 tidymodels 的用户。除了 initial_split 之外,还有 group_initial_splitinitial_time_split - undefined

10

在查看了所有发布在这里的不同方法后,我没有看到任何人利用TRUE/FALSE来选择和取消选择数据。因此,我想分享一种使用该技术的方法。

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

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

解释

R语言中有多种选择数据的方式,最常用的是使用正/负索引来选择/取消选择。然而,也可以使用 TRUE/FALSE 来进行选择/取消选择。

考虑以下示例。

# 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

1
我认为这是最优雅的本地R解决方案,没有外部包。 - Tripartio

7

只需使用强大的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
你是不是想在最后一行使用 Default[-train_index,] - Matt L.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接