将向量随机分成两个集合

6
我有一个长度为100的向量t,想把它分成30和70个值,但是这些值应该是随机选择的,并且不能重复。因此,这30个值中的任何一个都不允许在70个值的子向量中出现,反之亦然。
我知道R函数sample可以用来从向量中随机选择值,包括有放回和无放回。但是,即使我使用replace = FALSE,我也必须运行sample函数两次,一次选择30个值,一次选择70个值。这意味着其中一些30个值可能会在70个值中出现,反之亦然。
有什么建议吗?

我有点困惑。为什么不能使用 sample() 随机选择 30,然后再从除了 30 以外的所有元素中随机选择作为另一个集合呢?按照定义,这两个集合将是唯一的。 - Gavin Simpson
@GavinSimpson,这基本上就是我在回答中所做的,只是添加了一个分组变量来进行拆分;但是,我仍然不确定他们实际上正在寻找什么。 - A5C1D2H2I1M1N2O1R2T1
感谢您的所有答案!我尝试了不同的解决方案,它们似乎都有效。我刚刚发现了一个不同的R包:ftp://ftp.ee.freebsd.org/pub/pkgsrc/current/pkgsrc/math/R-e1071/README.html,它确实做到了我想要的。然而,我根本无法安装它。我下载了.tgz文件并尝试安装它,但失败了... - user969113
1
你正在使用FreeBSD吗? 如果没有,为什么要尝试安装它的tarballs?使用您的R版本提供的任何设施来安装软件包,但如果您有互联网,请启动R并输入 install.packages("e1071"), depend = TRUE) 来安装包,然后输入 library("e1071") 来加载它,准备在当前会话中使用。 - Gavin Simpson
您能否回复那些要求澄清您想要实现什么的评论?有些混淆了,如果t具有非唯一值,则大多数答案都将失败。 - Gavin Simpson
这里的所有答案都非常简单明了:我不确定为什么您想使用一个包来解决问题,除非它有其他您没有提到的并发生了复杂性。 - seancarmody
4个回答

8
这个怎么样:
t <- 1:100 # or whatever your original set is
a <- sample(t, 70)
b <- setdiff(t, a)

1
与其他条目相同的评论; setdiff()方法仅在isTRUE(all(!duplicated(t)))时有效。如果存在重复值,则会“失败”。 - Gavin Simpson
同意,但我怀疑OP有一个具有唯一值的向量(否则,避免重复抽样似乎就不那么重要了)。 - seancarmody
在这种情况下,一旦你有了第一个样本(比如30个),你可以通过负索引来获取其他的样本,你不需要使用setdiff()。对于这个任务来说,这有点过度杀伤力了,不是吗? - Gavin Simpson
t1:100时,但是上述方法适用于任何具有唯一条目的向量t。当然,另一种选择是坚持采样1:100并使用负索引,但是样本应表示索引而不是样本,就像您所做的那样。 - seancarmody

6
关于我的评论,有什么问题吗:
vec <- 1:100
set.seed(2)
samp <- sample(length(vec), 30)

a <- vec[samp]
b <- vec[-samp]

为了显示这些是没有重复的独立集合:

?

R> intersect(a, b)
integer(0)

如果您的向量中有重复的值,那就是另一回事了,但是您的问题不够清晰。
如果在vec中有重复项,情况会更加复杂,这取决于您想要实现什么结果。
R> set.seed(4)
R> vec <- sample(100, 100, replace = TRUE)
R> set.seed(6)
R> samp <- sample(100, 30)
R> a <- vec[samp]
R> b <- vec[-samp]
R> length(a)
[1] 30
R> length(b)
[1] 70
R> length(setdiff(vec, a))
[1] 41

因此,setdiff() 在这里“失败”了,因为它没有正确获取长度,但是 ab 包含重复的值(但不是从样本中观察到的)。
R> intersect(a, b)
 [1] 57 35 91 27 71 63  8 92 49 77

重复(交集)是由于原始样本vec中的值出现两次以上。

4
像这样的东西怎么样?
x <- 1:100
s70 <- sample(x, 70, replace=FALSE)
s30 <-sample(setdiff(x, s70), 30, replace=FALSE)
s30将与setdiff(x, s70)具有相同的数字,它们之间的区别在于:s30是一个长度为30的无序向量,而setdiff(x,s70)将给出一个长度为30的(升序)排序向量。您说您想要长度为70和30的随机子样本,因此s30比仅使用setdiff(x, s70)更好。如果顺序并不重要,那么更好的选择是按@seancarmody的答案使用没有samplesetdiff

1
Snap!虽然在第二个例子中你不一定需要样本,除非你想要打乱顺序,但这在原帖中并不是很清楚(“将数值分为30和70…”)。 - seancarmody

1

正如您提到的“分割”,您也可以尝试这样做:

set.seed(1)
t <- sample(20:40, 100, replace=TRUE)
groups <- rep("A", 100)
groups[sample(100, 30)] <- "B"
table(groups)
# groups
#  A  B 
# 70 30
split(t, groups)
# $A
#  [1] 25 32 39 24 38 39 33 21 24 23 36 40 27 36 24 33 22 25 28 28 38 27 30 30 23
# [26] 34 35 37 33 31 36 20 30 35 34 30 29 25 22 26 33 28 26 29 26 33 30 36 21 38
# [51] 27 37 27 27 30 38 38 36 29 34 28 26 35 25 23 25 21 33 36 28
# 
# $B
#  [1] 27 33 34 28 30 35 39 20 32 37 36 22 28 36 31 38 21 30 39 25 28 40 24 34 22
# [26] 38 36 29 37 32

我认为OP想要无重复的样本,并且第一个向量中的值不能包含在第二个向量中。对吧? - Jilber Urbina
@Jilber,我认为问题并不完全清楚。如果我使用我的“t”和你的答案或Sean的答案,第一步是正确的,但第二步不起作用。你有没有尝试过在1:100以外的数据上使用你的答案?我的假设是他们关心的是基于索引或位置选择数字,而不是值。 - A5C1D2H2I1M1N2O1R2T1
根据你的假设,你是正确的。是的,这个问题不够清晰。 - Jilber Urbina

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