我想生成一个随机列联表,边缘都相等。
最简单的例子就是拥有表格:
3 3 3 | 9
3 3 3 | 9
3 3 3 | 9
_ _ _
9 9 9
所以sum(r_i) = sum(c_j) =9
。我想找到符合这个标准的所有列联表,然后能够分析这组表的一些功能。
是否有一种“简单”的方式在R中生成这些表?
答案 0 :(得分:5)
你的问题并不完全准确。生成随机列联表很容易。查找符合这些条件的所有列联表可能更难,因为表的概率非常不均匀,需要一个非常大的样本以确保您拥有所有这些表。 (有人给出了基于partitions
包的确定性枚举解决方案的开头,但似乎已经删除了他们的答案......)r2dtable
包中的stats
(核心包样本随机表:
仅生成1个样本(结果以列表形式返回):
set.seed(101)
r2dtable(n=1,r=c(9,9,9),c=c(9,9,9))[[1]]
## [,1] [,2] [,3]
## [1,] 4 3 2
## [2,] 2 4 3
## [3,] 3 2 4
你的榜样有多大?
set.seed(102)
tList <- r2dtable(n=50000,r=c(9,9,9),c=c(9,9,9))
将结果转换为字符串以便于比较:
vals <- sapply(tList,function(x) paste(c(x),collapse=""))
有多少人?
length(unique(vals)) ## 1018
更新:更大的样本(n = 500000)提供了1276个唯一表格。这似乎在对称的基础上更合理,但可能不完整 - 基于对数频率分布,可能还有一个更长的尾巴我还没有被抓住。
实际上有:this web page提供了一种计算表数的方法;所有边距均为1540,等于9。
对数频率分布:
plot(log10(rev(sort(table(vals)))),type="l")
最常见的表:
head(rev(sort(table(vals))))
## vals
## 333333333 342324333 333324342 333342324 423333243 234333432
## 996 626 626 605 596 592
(为了额外的功劳,我应该尝试折叠对称案例。)
全部平等的可能性:
mean(vals=="333333333") ## 0.1992
确定性方法(我希望所有者将恢复)从compositions()
包中的partitions
函数开始,该函数枚举了将整数N
分区为{{n
的所有方法。 1}} components:compositions(9,3)
给出所有3个非负整数的集合,它们总和为9,表示应急矩阵中所有可能的行/列。
我还在考虑如何使用这些原材料并将它们结合起来列举表格:必须至少有1276个,所以它不仅仅是个别作品的所有排列(只会给3!* 55 = 330)。
这是一个开始,但实际上并不起作用:
library("partitions")
cc <- compositions(9,3)
too.many <- combn(split(cc,col(cc)),3,
FUN=function(x) do.call(cbind,x),
simplify=FALSE) ## 26235
ok <- sapply(too.many,function(x) all(rowSums(x)==9))
只有252好吗?也许我们需要允许这些结果的所有排列(这将允许252 * 6 = 1512,一个看似合理的结果......)?
答案 1 :(得分:1)
这可能是对这个问题的疯狂回答,这是一个疯狂的(也是不完整的)答案。但是,它与您的预期结果有关,也是数独的。这很有趣。
library("sudokuAlt")
g <- matrix(as.numeric(makeGame(3,0)), nrow = 9)
colSums(g)
# [1] 45 45 45 45 45 45 45 45 45
rowSums(g)
# [1] 45 45 45 45 45 45 45 45 45
基本上,数独谜题是您正在寻找的特定情况。这也增加了约束,即每行和每列不仅具有相同的边缘,而且具有完全相同的元素组合。这个软件包只能实现9x9,16x16或25x25的谜题,但您可以查看源代码,了解它们如何生成谜题,并可能从那里构建更通用的解决方案。