【发布时间】:2015-10-15 11:31:30
【问题描述】:
我希望生成一组数字的所有可能组合,但有多个约束。我在 Stack Overflow 上发现了几个类似的问题,但似乎都没有解决我的所有限制:
R: sample() command subject to a constraint
R all combinations of 3 vectors with conditions
Generate all combinations given a constraint
R - generate all combinations from 2 vectors given constraints
下面是一个示例数据集。无论如何,在我看来,这是一个确定性数据集。
desired.data <- read.table(text = '
x1 x2 x3 x4
1 1 1 1
1 1 1 2
1 1 1 3
1 1 2 1
1 1 2 2
1 1 2 3
1 1 3 3
1 2 1 1
1 2 1 2
1 2 1 3
1 2 2 1
1 2 2 2
1 2 2 3
1 2 3 3
1 3 3 3
0 1 1 1
0 1 1 2
0 1 1 3
0 1 2 1
0 1 2 2
0 1 2 3
0 1 3 3
0 0 1 1
0 0 1 2
0 0 1 3
0 0 0 1
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')
以下是限制条件:
- 第 1 列只能包含 0 或 1
- 最后一列只能包含 1、2 或 3
- 所有其他列可以包含 0、1、2 或 3
- 一旦非 0 出现在一行中,该行的其余部分就不能包含另一个 0
- 一旦 3 出现在一行中,则该行的其余部分只能包含 3
- 一行中的第一个非 0 数字必须是 1
我知道生成此类数据集的唯一方法是使用嵌套的for-loops,如下所示。我使用这种技术多年,最后决定问是否有更好的方法。
我希望这不是重复的,我希望它不会被认为过于专业。我经常创建这些类型的数据集,一个更简单的解决方案会很有帮助。
my.data <- matrix(0, ncol = 4, nrow = 25)
my.data <- as.data.frame(my.data)
j <- 1
for(i1 in 0:1) {
if(i1 == 0) i2.begin = 0
if(i1 == 0) i2.end = 1
if(i1 == 1) i2.begin = 1
if(i1 == 1) i2.end = 3
if(i1 == 2) i2.begin = 1
if(i1 == 2) i2.end = 3
if(i1 == 3) i2.begin = 3
if(i1 == 3) i2.end = 3
for(i2 in i2.begin:i2.end) {
if(i2 == 0) i3.begin = 0
if(i2 == 0) i3.end = 1
if(i2 == 1) i3.begin = 1
if(i2 == 1) i3.end = 3
if(i2 == 2) i3.begin = 1
if(i2 == 2) i3.end = 3
if(i2 == 3) i3.begin = 3
if(i2 == 3) i3.end = 3
for(i3 in i3.begin:i3.end) {
if(i3 == 0) i4.begin = 1 # 1 not 0 because last column
if(i3 == 0) i4.end = 1
if(i3 == 1) i4.begin = 1
if(i3 == 1) i4.end = 3
if(i3 == 2) i4.begin = 1
if(i3 == 2) i4.end = 3
if(i3 == 3) i4.begin = 3
if(i3 == 3) i4.end = 3
for(i4 in i4.begin:i4.end) {
my.data[j,1] <- i1
my.data[j,2] <- i2
my.data[j,3] <- i3
my.data[j,4] <- i4
j <- j + 1
}
}
}
}
my.data
dim(my.data)
这是输出:
V1 V2 V3 V4
1 0 0 0 1
2 0 0 1 1
3 0 0 1 2
4 0 0 1 3
5 0 1 1 1
6 0 1 1 2
7 0 1 1 3
8 0 1 2 1
9 0 1 2 2
10 0 1 2 3
11 0 1 3 3
12 1 1 1 1
13 1 1 1 2
14 1 1 1 3
15 1 1 2 1
16 1 1 2 2
17 1 1 2 3
18 1 1 3 3
19 1 2 1 1
20 1 2 1 2
21 1 2 1 3
22 1 2 2 1
23 1 2 2 2
24 1 2 2 3
25 1 2 3 3
26 1 3 3 3
编辑
抱歉,我最初忘记包含约束 #6。
【问题讨论】:
-
@nongkrong 好点。我需要添加另一个约束:第一个非 0 数字必须是 1。
-
d <- expand.grid(list(0:1,0:2,0:3,1:3))这涵盖了 1,2 和 3。4-6,我认为您必须逐行进行。我想不出任何diff()或cumsum()魔法可以模仿。 -
如果您不将其转换为 for 循环之前的 data.frame 并像这样一次分配每一行
my.data[j,1]<-c(i1,i2,i3,i4)在您的示例中,您可以提高 for 循环组的效率'd 必须将矩阵初始化为 26 行而不是 25 行。
标签: r