将Matlab中矩阵的每一行与其余行进行比较

时间:2017-03-23 11:09:32

标签: matlab

我在Matlab中有一个零A的矩阵BxM和一个维A的矩阵。

具体而言,M包含B=2^M空间中1和0的所有可能处置,同时考虑到顺序(因此,i=1,...,N)。

  • 构建矩阵,对于A(i,:)>A(j,:)的任何A(i,:)><A(j,:)j=i+1,...,NA(i,:)>=A(j,:)
  • 撰写A(i,h)>=A(j,h)表示h=1,...,M的{​​{1}}。
  • A(i,:)>A(j,:)表示A(i,h)>=A(j,h)的{​​{1}},至少有一个h=1,...,M严重不等。
  • h意味着无法确定A(i,:)><A(j,:)还是反之。

例如A(i,:)>=A(j,:)

M=3

考虑

  A=[1 1 1;
     1 1 0;
     1 0 1;
     1 0 0;
     0 1 1;
     0 1 0;
     0 0 1;
     0 0 0];

对于B=cell(2^M, 2^M); A的任意两个可比较行,我希望A(i,:)>A(j,:)包含所有行B{i,j},以便A(k,:)

在上面的示例中,所需的输出将是

A(j,:)<A(k,:)<A(i,:)

此代码执行我想要的操作

B{1,4}=[1 1 0; 1 0 1];
B{1,6}=[1 1 0; 0 1 1];
B{1,7}=[1 0 1; 0 1 1];
B{1,8}=[1 1 0; 1 0 1; 1 0 0; 0 1 1; 0 1 0; 0 0 1];
B{2,8}=[1 0 0; 0 1 0];
B{3,8}=[1 0 0; 0 0 1];
B{5,8}=[0 0 1; 0 1 0];

但是,上面的代码是不可行的,因为在我的实际案例中B=cell(2^M, 2^M); for j=1:size(A,1) for h=1:size(A,1) if sum(A(j,:)==A(h,:))~=M && sum(A(j,:)>=A(h,:))==M %if A(j,:)>A(h,:) according to the meaning indicated above B{j,h}=A(any(bsxfun(@ne, A,A(j,:)),2) & any(bsxfun(@ne, A,A(h,:)),2) &... all((bsxfun(@le, A,A(j,:)) & bsxfun(@ge, A,A(h,:))),2),:); end end end 。你有没有可能加快它的建议,如果是的话,怎么样?

代码的一个主要问题是,对于M=20,它需要预先分配一个明确无法完成的单元格M=20

另一方面,在双循环结束时,很多单元格都是空的(因为许多行对不满足if条件),而我真正需要的是保持轨道内容和仅非坐标的坐标。因此,也许,“稀疏细胞”可以帮助我。

任何建议都会非常感激。

4 个答案:

答案 0 :(得分:2)

而不是预先计算和记忆A矩阵(“Old Matlab Style”),

编写一个“生成器函数”,为任何行索引提供A矩阵的行内容。这样,您就可以将内存密集型问题转换为CPU密集型问题。最重要的是,子结果彼此独立。

所以你需要的是

A_by_row=@(rowIdx)(....)

这样就不需要大量的RAM了,你可以将你的问题分发给parfor,GPU甚至多个节点,然后结合子范围的子结果。

试试这个:

ListIdx=0; 
for j=1:B 
 for h=1:B 
  if sum(A_by_row(j)==A_by_row(h))~=M, 
    ListIdx=ListIdx+1, 
    B_List(ListIdx).Coordinates=[j,h],     
    B_List(ListIdx).Result=**YourCodeThatMakesAnArbitraryLengthVec‌​tor**, 
  end, 
 end, 
end 

这样,在结构“列表”中,您将获得每个条目的坐标和答案向量。

祝你好运。

答案 1 :(得分:2)

我们可以做更多的数学运算,预测测试结果,然后保存预测,而不是强力解答。

我们将做出以下假设:

1)在数组A中,索引位置'n'存储'n'的二进制表示。例:A(3)= [0,1,1]

2)因为A(j)不能等于A(h),A(j)的二进制表示也不能总是小于A(h),结果必须是低三角形。

3)在绘制M = 5的结果位置后,我们看到符合条件创建了一个分形图案。这个分形可以使用Lucas对应定理重建,“AND(NOT(j),h)= binomial_coefficient(j,h)mod(2)”

4)以下功能会复制您的结果。

list.R<- c("EastAsia", "Europe", "Oceania", "SouthAsia")
for (i in list.R){
read.table(paste(i,"-Levant",".txt",sep=""), header = F) -> tbl
colnames(tbl)<-c("CHR", "SNP", "COORD", "CLST1", "MAF1", "CLST2", "MAF2")

require(ggplot2)
plot <- ggplot(data = tbl,aes(x = MAF1, y = MAF2)) + geom_point(size=1) + geom_abline(intercept = 0, slope = 1) + coord_fixed() +
  labs(x = paste("Allele frequency from ",i,sep=""),y = "Allele frequency from the Levant")

ggsave(plot=plot,height=8,width=8, filename=paste(i,"-Levant",".pdf",sep=""), useDingbats=FALSE)
plot(plot)
dev.off()
}

建议您以紧凑的形式存储B,或使用预测在存储(2 ^ 20)^ 2信息单元的leu中根据需要提取数据。

如果符合您的要求,请告知我们。

答案 2 :(得分:2)

我将把你的问题分成3个。

  1. 查找B
  2. 所需的尺寸
  3. 在A中找到所有可比较的行对,其间至少有一行(B的左手部分)
  4. 在每个可比较对之间找到A的所有行(B的右手部分)
  5. 我将使用的一些概念

    • 汉明重量:连续1的数量
    • 汉明距离:行之间的不同值的数量

    第1部分

    我们知道行 i j 具有可比性,并且当且仅当符合 i &gt; j i 中的任何0在 j 中也是零,而 j 中的任何1在 i 中也是1 。意味着 i 的汉明重量总是要大于 j的汉明重量

    我们也知道如果 i j 之间的汉明距离是1,那么它们之间的行集将是空的。

    因此,对于任何 i ,我们可以通过将其1中的至少两个翻转为0来找到其可行的 j &#s; s

    由于我们还不关心订单,因此具有相同汉明重量的任何 i 将具有相同数量的可行 j 。如果 i 的汉明重量为1或0,则没有可行的 j ,因为没有两个1可以翻转

    现在,我们可以找到给定汉明重量 i w的可行 j 的数量,它们是给定的汉明距离d,使用函数nchoosek(w,d)。我们知道有用的 i 的汉明重量从2到M,有用的汉明距离从2到w

    因此,我们可以生成大小为n_j x M的矩阵M,其中行将指示汉明重量和汉明距离列。

    n_j = zeros(M);
    
    for w=2:20
        for d=2:w
            n_j(w,d) = nchoosek(w,d);
        end
    end 
    

    如果我们对每一行求和,我们将获得具有给定汉明权重的每个 i 的可用 j 的数量。

    我们还可以找到A中有多少 i 具有给定有用的汉明重量,因为它已经完成并且每种组合都有可能。我们可以再次使用nchoosek

    n_i = zeros(M,1);
    
    for w=2:M
        n_i(w) = nchoosek(M,w);
    end
    

    现在我们可以通过将每个汉明重量上可能的 i 的数量乘以可能的 ij > j 关于每个汉明重量。

    sum(n_i .* sum(n_j,2))
    

    在M = 20的情况下,这是巨大的,它是3.4753 e09。而这只是对的数量,我们仍然需要找到每对之间的行数。它仍然是2 ^ 20 x 2 ^ 20的改进,但我会考虑我的选择。

    继续,我们可以找到两对之间的行数作为每对的汉明距离的函数。基本上它的2^d -2来自汉明距离表示你可以翻转以获得新的有效行的值的数量,减去两个原始行 i j

    由于我们保持原始的n_j也被汉明重量分开,我们可以将它们相乘。

    n_r = 2.^(1:M) - 2;
    
    sum(sum((n_i*n_r).*n_j))
    

    对于M = 20的情况,其为1.0925 e12。这意味着B必须长度为3.4753 e09并且保持1.0925 e12值,这是我不会尝试的顺序

    第2部分

    现在生成所有对 ij 。我相信生成一个我们输入 i 的函数会更容易,更快,它会返回有效的 j

    您说您已经拥有A,因此您可以直接将其编入索引,但我会使用de2bibi2de函数将索引i与每行A_row_i相关联

    A_row_i = de2bi(2^M - i, M)
    
    i = 2^M - bi2de(A_row_i)
    

    首先要计算行i的汉明重量,并使用它来获取我们期望的 j 的数量。

    w = sum(A_row_i);
    
    j_s = n_j(w,:);
    

    j_s将是一个大小为M的向量,它可以为我们提供在给定汉明距离内可以获得的 j 的数量。

    可以修改code from this answer以创建大小为flips x sum(j_s)的矩阵w,并在A_row_i中完成所有必要的翻转1 {}获得A_row_j

    的矩阵
    flips=[];
    
    for d=2:M
        c = nchoosek(1:w,d);
        out = ones(j_s(d),w);
        out(sub2ind([j_s(d),w],(1:j_s(d))'*ones(1,d),c))=0;
        flips = [flips;out];
    end
    

    此时值得注意的是flips仅依赖于w,而不依赖于i,因此只有M-2个不同的。{1}}。理论上,您可以预先计算它们以加速代码。

    既然我们已经完成了1到1的翻转,我们只需要将它们应用到A_row_i的副本并恢复j的值

    A_row_j = repmat(A_row_i,[sum(j_s),1]);
    A_row_j(A_row_j==1) = flips;
    
    j = 2^M - bi2de(A_row_j);
    

    现在j包含相应 i 的所有有效 j

    你现在可以循环遍历从1到2 ^ M的所有值并且构建B正在进行中,它将比双循环更好,但是对于M = 20,它将会是一段时间。

    第3部分

    如果我们有有效的 i j ,那么获取行之间的索引k并不困难。首先,我们计算dA_row_i之间的汉明距离A_row_j,并使用它来创建一个类似于flips的矩阵,它将帮助我们构建{{1}的所有值并恢复索引A_row_k

    要翻转的值是kA_row_i彼此不同的值,我们可以使用A_row_j

    轻松找到这些值
    bitxor

    现在你可以遍历B,或者每次为每个 i 获取 j 时运行此代码,无论哪种方式对您有效。< / p>

    作为结论,我真的建议将其保留为生成器,并在需要值时调用它们,因为对于M = 20,所需的内存量是不切实际的。

答案 3 :(得分:0)

简单的数学问题!

Function out=A(row , number_of_bits)
        out=~bitget(row-1,number_of_bits:-1:1);
end

A(3,3)
ans =
     1     0     1 %which is identical with your A(3,:)

<强> B:

function [out]=B(n1,n2,number_of_bits)
   c1=A(n1,number_of_bits);
   c2=A(n2,number_of_bits);
   out=zeros(1,number_of_bits);
   out((c1==0)&(c2==1))=-1;
   if sum(out)>=0
      out=zeros(1,number_of_bits)+2;
      out(c1==0)=0;
      out(c2==1)=1; 
      out=int8(out);
   else
      out=[];
   end

%example:
B(1,4,3)
ans =
     1     2     2 %number 2 serves as wildcard ("*") and means that element could be either 0 or 1, you should discard A(1,:) and A(4,:) from the results so the actual size_of_B is (2^ number_of_wildcards)-2

示例:

B(1,1000000,20) 
ans =
  Columns 1 through 10
     2     2     2     2     1     2     1     1     1     1
  Columns 11 through 20
     2     1     1     1     2     2     2     2     2     2
  %which means that B(1,1000000) has (2^12)-2=4094 rows 

B(1,2,20)
ans =
  Columns 1 through 10
     1     1     1     1     1     1     1     1     1     1
  Columns 11 through 20
     1     1     1     1     1     1     1     1     1     2
  %which means that B(1,2) has (2^1)-2=0 rows 

<强> size_of_B:

function out=size_of_B(b)
     if numel(b)==0
        out=0;
     else
        b(~(b==2))=0;
        b(~(b==0))=1;
        out=(2^sum(b))-2;
     end
%example:
size_of_B(B(1,1000000,20))
ans =
        4094

有(2 ^ 19)*((2 ^ 20)-1)〜= 5e11对i,j用于迭代 如果你有一个没有做任何事情的for循环它会得到:1100秒!所以计算所有非空B的时间量是巨大的(即使我们知道在计算之前我们知道B的哪个元素是非空的)

tic; 
 for i=1:1:10^9 
 end 
 toc
Elapsed time is 2.218067 seconds.
tic; 
 for i=1:1:10^10
 end 
 toc
Elapsed time is 22.165445 seconds.
%example:
 tic;
 M=10;
 n=1;
 for i=1:2^M
     for j=1:2^M
         if i<j
             c=B(i,j,M);
             if ~(size_of_B(c)==0)
                 d(n,:)=c;
                 n=n+1;
             end
         end
     end
 end
 toc
 [s,~]=size(d);
 s
Elapsed time is 10.095085 seconds. 
s =
          52905 %for M=10 there is 52905 pair of i,j with non-empty-B values;

对于M = 20,它需要大约10 * 4 ^ 10~ = 10M秒〜= 121天! (如果内存允许)

%script for plotting number of non-empty-B versus M
  d=[];
 for M=1:10
     tic;
     n=1;
     for i=1:2^M
         for j=1:2^M
             if i<j
                 c=B(i,j,M);
                 if ~(size_of_B(c)==0)
                     d(n,:)=c;
                     n=n+1;
                 end
             end
         end
     end
     toc
     [s,~]=size(d);
     d=[];
     h(M)=s;
 end
Elapsed time is 0.005418 seconds.
Elapsed time is 0.002238 seconds.
Elapsed time is 0.000933 seconds.
Elapsed time is 0.003058 seconds.
Elapsed time is 0.011650 seconds.
Elapsed time is 0.044217 seconds.
Elapsed time is 0.170286 seconds.
Elapsed time is 0.696161 seconds.
Elapsed time is 3.024212 seconds.
Elapsed time is 15.836280 seconds.
>> plot(h,'-o')

从图中估计我们可以发现,对于M = 20,存在约〜3e9个非空B值; (并且至少需要大约20~60 GB的内存来存储B值,比如我使用的通配符样式,如果你想要写出没有通配符样式的所有B,那么还要多得多) enter image description here

最后我可以提一下,使用简单的算法可以计算出非空B的确切数量!