我希望生成一组数字的所有可能组合,但具有多个约束。我在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')
以下是限制因素:
我知道生成此类数据集的唯一方法是使用嵌套的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。
答案 0 :(得分:0)
与@mrip类似,从expand.grid
开始,它可以处理前3个约束,因为它们不与其他列交互
step1<-expand.grid(0:1,0:3,0:3,1:3)
接下来我会过滤它。这种方法与mrip的区别在于我的过滤是一次应用而不是3次,因此 的过滤速度要快3倍左右。
filtered<-step1[apply(step1,1,function(x) all(if(length(which(x==0))>0) {max(which(x==0))==length(which(x==0))} else {TRUE}, if(length(which(x==3))>0) {min(which(x==3))==length(x)-length(which(x==3))+1} else {TRUE}, x[!x%in%0][1]==1)),]
那应该是它。如果你想在这里检查apply中的每个元素,那就是:
if(length(which(x==0))>0) {max(which(x==0))==length(which(x==0))} else {TRUE}
如果有任何零,则确保零之前没有任何内容
if(length(which(x==3))>0) {min(which(x==3))==length(x)-length(which(x==3))+1} else {TRUE}
如果有任何3,它确保没有任何东西在它们之后。
x[!x%in%0][1]==1)
这首先过滤掉行中的零,然后在该过滤器之后获取行的第一个元素,并且只允许它为一个。
答案 1 :(得分:0)
以下是为此特定示例创建所需数据集的代码。我怀疑代码可以推广。如果我成功推广它,我会发布结果。虽然代码很乱并且不直观,但我确信有一个基本的一般模式。
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')
n <- 3 # non-zero numbers
m <- 4-2 # number of middle columns
x1 <- rep(1:0, c(((n*(n-1)) * (n-1) + n), (n*(n-1) + n + (n-1))))
x2 <- rep(c(1:n, 1:0), c(n*m+1, n*m+1, 1, n*m+1, n*1+1))
x3 <- rep(c(rep(1:n, n-1), n, 1:n, 1:0), c(rep(c(n,n,1), n-1), 1, n,n,1, n,1))
x4 <- c(rep(c(rep(1:n, (n-1)), n), (n-1)), n, rep(1:n,(n-1)), n, 1:n, 1)
my.data <- data.frame(x1, x2, x3, x4)
all.equal(desired.data, my.data)
# [1] TRUE
答案 2 :(得分:0)
我会使用expand.grid
生成所有组合然后对其进行子集,一次一个约束:
x<-expand.grid(0:1,0:3,0:3,1:3)
## Once a non-0 appears in a row the rest of that row cannot contain another 0
b1<-apply(x,1,function(z) min(diff(z!=0))==0)
x<-x[b1,]
## Once a 3 appears in a row the rest of that row must only contain 3's
b1<-apply(x,1,function(z) min(diff(z==3))==0)
x<-x[b1,]
## The first non-0 number in a row must be a 1
b1<-apply(x,1,function(z) {
w<-which(z==0)
length(w)==0 || z[tail(w,1)+1]==1
})
x<-x[b1,]
现在排序:
x<-x[order(x[,1],x[,2],x[,3],x[,4]),]
x
输出:
Var1 Var2 Var3 Var4
1 0 0 0 1
9 0 0 1 1
41 0 0 1 2
73 0 0 1 3
11 0 1 1 1
43 0 1 1 2
75 0 1 1 3
19 0 1 2 1
51 0 1 2 2
83 0 1 2 3
91 0 1 3 3
12 1 1 1 1
44 1 1 1 2
76 1 1 1 3
20 1 1 2 1
52 1 1 2 2
84 1 1 2 3
92 1 1 3 3
14 1 2 1 1
46 1 2 1 2
78 1 2 1 3
22 1 2 2 1
54 1 2 2 2
86 1 2 2 3
94 1 2 3 3
96 1 3 3 3