组合任意数量矩阵的每个列组合

Combining every column-combination of an arbitrary number of matrices

我正在想办法做某事 "reduction" 我有一个 varying 个大小为 varying 的矩阵,例如

1 2 2 2 5 6...70 70
3 7 8 9 7 7...88 89

1 3 4
2 7 7
3 8 8
9 9 9

.
.

44 49 49 49 49 49 49
50 50 50 50 50 50 50
87 87 88 89 90 91 92

我需要做的(我希望我解释得足够清楚)是将 任何可能的 来自这些矩阵的列 的组合,这意味着一列可能是

1
3
1
2
3
9

.
.
.

44
50
87

这将减少到

1
2
3
9
.
.
.
44
50
87

我之所以这样做是因为我需要找到最小的唯一组合列

我想要完成什么

对于那些感兴趣的人,我正在尝试找到最小的基因敲除集 禁用反应。这里,每个矩阵代表一个反应,列代表 会禁用该反应的基因。

该方法可以根据需要蛮力,因为这些矩阵很少变得非常大, 而且反应组合也不会很长

问题

我不能(据我所知)用任意数量的迭代器创建一个 for 循环,以及 矩阵(对禁用的反应)是任意的。

澄清

如果我有矩阵 A、B、C,列为 a1、a2...b1、b2...c1...cn 我需要什么 是列 [a1 b1 c1], [a1, b1, c2], ..., [a1 b1 cn] ... [an bn cn]

解决方案 由下方 提供。

他的回答的扩展,为了完整性

他的解决方案以

结束
MyProd = product(Array_of_ColGroups...)

哪个完成了工作

然后从他停下的地方继续

collection = collect(MyProd); #MyProd is an iterator
merged_cols = Array[] # the rows of 'collection' are arrays of arrays

for (i,v) in enumerate(collection)
    # I apologize for this line
    push!(merged_cols, sort!(unique(vcat(v...)))) 
end

# find all lengths so I can find which is the minimum
lengths = map(x -> length(x), merged_cols);

loc_of_shortest = find(broadcast((x,y) -> length(x) == y, merged_cols,minimum(lengths)))

best_gene_combos = merged_cols[loc_of_shortest]

好的,让我们看看我是否理解这一点。您有 n 个矩阵,并希望所有组合都与每个 n 矩阵中的一列相结合?如果是这样,Iterators 包中的 product()(对于笛卡尔积)怎么样?

using Iterators

n = 3
Array_of_Arrays = [rand(3,3) for idx = 1:n] ## arbitrary representation of your set of arrays.
Array_of_ColGroups = Array(Array, length(Array_of_Arrays))

for (idx, MyArray) in enumerate(Array_of_Arrays)
    Array_of_ColGroups[idx] = [MyArray[:,jdx] for jdx in 1:size(MyArray,2)]
end

MyProd = product(Array_of_ColGroups...)

这将创建一个迭代器对象,然后您可以遍历该对象以考虑列的特定组合。

tl;dr - 完整的解决方案:

# example matrices
a = rand(1:50, 8,4); b = rand(1:50, 10,5); c = rand(1:50, 12,4);
Matrices = [a,b,c];

toJagged(x) = [x[:,i] for i in 1:size(x,2)];
JaggedMatrices = [toJagged(x) for x in Matrices];

Combined = [unique(i) for i in JaggedMatrices[1]];
for n in 2:length(JaggedMatrices)
  Combined = [unique([i;j]) for i in Combined, j in JaggedMatrices[n]];
end

Lengths         = [length(s) for s in Combined];
Minima          = findin(Lengths, min(Lengths...));
SubscriptsArray = ind2sub(size(Lengths), Minima);
ComboTuples     = [((i[j] for i in SubscriptsArray)...) for j in 1:length(Minima)]

解释:

假设您有矩阵 ab

a = rand(1:50, 8,4);
b = rand(1:50, 10,5);

将它们表示为锯齿状数组,列在前

A = [a[:,i] for i in 1:size(a,2)];
B = [b[:,i] for i in 1:size(b,2)];

使用列表理解连接所有列组合的行;当场删除重复项:

Combined = [unique([i;j]) for i in A, j in B];

您现在拥有 a 和 b 的所有列组合,作为已删除重复项的串联行。轻松找到长度:

Lengths = [length(s) for s in Combined];

如果您有两个以上的矩阵,请在 for 循环中迭代执行此过程,例如通过使用 Combined 矩阵代替 a。例如如果你有一个矩阵 c:

c = rand(1:50, 12,4);
C = [c[:,i] for i in 1:size(c,2)];
Combined = [unique([i;j]) for i in Combined, j in C];

一旦您将长度数组作为多维数组(与输入矩阵一样多的维度,其中每个维度的大小是每个矩阵中的列数),您可以找到对应于最低的列组合值(可能有不止一种组合),通过简单的 ind2sub 操作:

Minima = findin(Lengths, min(Lengths...));
SubscriptsArray = ind2sub(size(Lengths), Minima)

(例如,对于具有 3 个输入矩阵的随机 运行,我碰巧得到 4 个结果,最小长度为 19。ind2sub 的结果是 ([4,4,3,4,4],[3,3,4,5,3],[1,3,3,3,4])

您可以将其进一步转换为具有(有点难看)列表理解的 "Column Combination" 元组列表:

ComboTuples = [((i[j] for i in SubscriptsArray)...) for j in 1:length(Minima)]
# results in:
#   5-element Array{Tuple{Int64,Int64,Int64},1}:
#   (4,3,1)
#   (4,3,3)
#   (3,4,3)
#   (4,5,3)
#   (4,3,4)