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

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个回答

6

scorecard 包中有一个非常实用的函数,可以指定比率和种子。

library(scorecard)

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

测试和训练数据被存储在一个列表中,可以通过调用 dt_list$traindt_list$test 来访问。

5
如果您输入:
?sample

如果会启动一个帮助菜单,解释示例函数的参数含义。

虽然我不是专家,但这是一些我所拥有的代码:

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

这将为您提供75%的训练和25%的测试。

4

我的解决方案是打乱行,然后将前75%的行作为训练数据,最后25%的行作为测试数据。非常简单!

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

3
我们可以将数据按照特定比例划分,这里是80%的训练数据和20%的测试数据集。
ind <- sample(2, nrow(dataName), replace = T, prob = c(0.8,0.2))
train <- dataName[ind==1, ]
test <- dataName[ind==2, ]

1
请注意,这是基于概率的,因此使用它不会总是创建精确的80-20%拆分。最简单的方法就是像上面提到的那样使用caret包中的createDataPartition。例如,仅连续运行3次后,我得到了45个训练样本和50个测试样本中的5个(90-10)。 - user21398

2
假设您有一个数据框 df,并且您想创建 75% 的训练集和 25% 的测试集。
all <- 1:nrow(df)
train_i <- sort(sample(all, round(nrow(df)*0.75,digits = 0),replace=FALSE))
test_i <- all[-train_i]

然后创建训练和测试数据框。
df_train <- df[train_i,]
df_test <- df[test_i,]

2

使用R中的caTools包,示例代码如下:

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

2

使用基础R。函数runif从0到1生成均匀分布的值。通过改变截断值(例如下面示例中的train.size),您将始终具有大约相同百分比的随机记录低于截断值。

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

如果这个回答能够展示额外的几行代码来创建训练集和测试集(新手经常会遇到困难),那么它将是一个更好的回答。 - Gregor Thomas

2
下面是一个函数,可以创建一个相同大小的子样本列表,虽然不完全符合您的要求,但对于其他人可能会有用。在我的情况下,用于创建多个分类树,以测试过度拟合问题。
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)
}

例子:

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

1

如果你想要可重复的结果,请注意使用 sample 进行拆分。即使使用了 set.seed,如果数据稍有变动,拆分仍会有所不同。例如,假设你的数据中按ID排序的列表是1到10之间的所有数字。如果你只删除了一个观察值(比如4),按位置抽样将产生不同的结果,因为现在5到10都移动了位置。

另一种方法是使用哈希函数将ID映射到一些伪随机数,然后在这些数的模上进行抽样。这种抽样更加稳定,因为分配现在是由每个观察值的哈希决定的,而不是由它相对位置决定的。

例如:

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

样本大小并不完全是5000,因为分配是概率性的,但在大样本中应该不会成为问题,这要归功于大数定律。

另请参阅:http://blog.richardweiss.org/2016/12/25/hash-splits.htmlhttps://crypto.stackexchange.com/questions/20742/statistical-properties-of-hash-functions-when-calculating-modulo


已添加为单独的问题:https://stackoverflow.com/questions/52769681/reproducible-splitting-of-data-into-training-and-testing-in-r - dzeltzer
我想从多个时间序列数据中开发auto.arima模型,并且我想使用每个系列的2年间隔中的1年数据、3年数据、5年数据、7年数据等来构建模型,并在剩余的测试集中进行测试。如何进行子集筛选,以便拟合的模型符合我的要求?非常感谢您的帮助。 - Stackuser

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)
sample.split()函数将向数据框添加一个名为'split1'的额外列,其中2/3的行将具有TRUE值,其余行将具有FALSE值。现在,split1为TRUE的行将被复制到train数据框中,而其他行将被复制到test数据框中。请注意保留HTML标签。

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