如何在生成Expand Grid(幂集)时预先施加约束规避内存问题
当然可以!直接生成符合约束的子集比先造全量幂集再过滤高效太多——尤其是当你的维度取值范围很大的时候,后者完全可能直接把内存撑爆。这里有几种实用的实现方式,用你熟悉的data.table就能轻松搞定:
方法一:拆分条件,分别生成后合并
核心思路是把你的约束拆成两个互斥的部分,分别生成符合条件的组合,最后合并起来:
- 当
w == 1时,d可以取1-5的所有值 - 当
w > 1时,d只能取1-2
对应的data.table代码:
library(data.table) # 生成w=1的所有d组合 part1 <- data.table(d = 1:5, w = 1) # 生成w=2、3且d=1、2的组合 part2 <- data.table(expand.grid(d = 1:2, w = 2:3)) # 合并两部分得到最终结果 Vmat_filtered <- rbind(part1, part2)
这种方法的优势是完全不会生成多余的行,从根源上避免了内存浪费。哪怕d的取值范围是10万、w是1000,也只会生成10万 + 2*999行,和全量的1亿行比,内存占用差了好几个数量级。
方法二:用data.table的CJ函数(简化写法)
如果你觉得拆分有点麻烦,也可以用data.table的CJ(交叉连接)函数,它比base R的expand.grid更高效。不过这里要注意:CJ还是会先生成笛卡尔积,但如果你的维度取值范围不大,这种写法会更简洁:
library(data.table) Vmat_filtered <- CJ(d = 1:5, w = 1:3)[w == 1 | (w > 1 & d < 3)]
不过如果维度很大,还是推荐第一种拆分方法,毕竟CJ还是会先创建全量集合,只是过滤的效率比base R高一些。
验证结果
运行上面的代码后,你会得到和过滤后完全一致的结果:
d w 1: 1 1 2: 2 1 3: 3 1 4: 4 1 5: 5 1 6: 1 2 7: 2 2 8: 1 3 9: 2 3
内容的提问来源于stack exchange,提问作者wolfsatthedoor
相关产品推荐
相关产品推荐

