Mata:创建一个矩阵,其中包含3个矩阵的所有元素的平均值

时间:2014-08-23 22:52:12

标签: nested-loops stata

定义三个行向量,     A =(1,2,3)     B =(10,20,30,40)     C =(100,200,300,400,500)

我想构建一个新的矩阵D,它将具有3x4x5 = 60个元素并包含这些元素的平均值,如下所示:

D = 
(1+10+100)/3, (1+10+200)/3,…, (1+10+ 500)/3 \
(1+20+100)/3, (1+20+200)/3,…, (1+20+ 500)/3 \
(1+30+100)/3, (1+30+200)/3,…, (1+30+ 500)/3 \
(1+40+100)/3, (2+40+200)/3,…, (2+40+ 500)/3 \

(2+10+100)/3, (2+10+200)/3,…, (2+10+ 500)/3 \
(2+20+100)/3, (2+20+200)/3,…, (2+20+ 500)/3 \
(2+30+100)/3, (2+30+200)/3,…, (2+30+ 500)/3 \
(2+40+100)/3, (2+40+200)/3,…, (2+40+ 500)/3 \

(3+10+100)/3, (3+10+200)/3,…, (3+10+ 500)/3 \
(3+20+100)/3, (3+20+200)/3,…, (3+20+ 500)/3 \
(3+30+100)/3, (3+30+200)/3,…, (3+30+ 500)/3 \
(3+40+100)/3, (3+40+200)/3,…, (3+40+ 500)/3 \

在这个例子中它的设置方式是12x5矩阵,但如果它是1X60矢量或60X1矢量我就没问题了。

如何在Mata中有效地完成这项工作?我是Mata的新手,我使用多个forval循环在Stata中运行(在这种情况下,会有3个forval循环)。但这变得非常耗时,因为我有多达8个行向量和每个向量约120个元素。

我认为我可以在Mata中使用for循环并且它会更快,但我相信如果我可以将其作为矩阵操作而不是使用for循环,那么它将是均匀的快点。问题是我很难想象如何编写这样的程序(或者甚至可能),任何帮助都会受到高度赞赏。

2 个答案:

答案 0 :(得分:1)

对于较小的示例,您基本上要求的是Kronecker产品的总和版本。我在这个主题上发现了这个Matlab讨论thread,其中它被称为Tensor Sum(没有经常使用这个短语)。

这是在Mata中复制操作的快速尝试。不是一个非常简洁的代码,所以随时编辑或更正。

clear
mata
// input data
A=(1,2,3)'                  // 3x1
B=(10,20,30,40)'            // 4x1
C=(100,200,300,400,500)'    // 5x1

// tensor sum for A and B
a=J(1,4,1)  // 1x4 with values of 1
b=J(1,3,1)  // 1x3 with values of 1
T=(A#a)+(b#B)'
T           // 3x4
T=vec(T)    // 12x1

// tensor sum for T and C
c=J(1,12,1) // 1x12 with values of 1
t=J(1,5,1)  // 1x5 with values of 1
T=(C#c)+(t#T)'

// divide by 3
T=T/3
T'  // transposed just for better display
end

答案 1 :(得分:1)

@AspenChen的聪明解决方案比for循环提供了巨大的速度提升,如某些测试所示:

clear all
set more off

mata

timer_clear() 

//----- change data -----

fa = 250
fb = fa + 1
fc = fa + 2


//----- Method 1 -----

timer_on(1)

A = (1..fa)                 // 1 x fa
B = (1..fb)*10              // 1 x fb
C = (1..fc)*100             // 1 x fc

F = J(1, cols(A) * cols(B) * cols(C), .)
col = 0
for (i=1; i<=cols(A); i++) {
    for (j=1; j<=cols(B); j++) {
        for (k=1; k<=cols(C); k++) {

            col++
            F[1,col] = A[1,i] + B[1,j] + C[1,k]

        }   
    }
}

timer_off(1)


//----- Method 2 (Aspen Chen) -----

timer_on(2)

A = (1::fa)                 // fa x 1
B = (1::fb)*10              // fb x 1
C = (1::fc)*100             // fc x 1

// tensor sum for A and B
a = J(1,rows(B),1)          // 1 x fb with values of 1
b = J(1,rows(A),1)          // 1 x fa with values of 1
T = (A#a) + (b#B)'          // fa x fb

T = vec(T)                  // fa*fb x 1

// tensor sum for T and C
c = J(1,rows(T),1)          // 1 x fa*fb with values of 1
t = J(1,rows(C),1)          // 1 x fc with values of 1
T = (C#c) + (t#T)'          // fc x fa*fb

timer_off(2)

timer()

end

导致:

timer report
  1.       8.78 /        1 =     8.776
  2.       .803 /        1 =      .803

如果原始海报仍然想要使用for循环,因为要比较大量的元素,他可以使用以下内容:

<snip>

larger = 0
for (i=1; i<=cols(A); i++) {
    for (j=1; j<=cols(B); j++) {    
        for (k=1; k<=cols(C); k++) {

            larger = larger + (A[1,i] + B[1,j] + C[1,k] > 7)

        }   
    }
}

larger

<snip>

修改

仅使用for循环进行进一步测试:

clear all
set more off

mata

timer_clear() 

//----- change data -----

fa = 500
fb = fa + 1
fc = fa + 2


//----- Method 1 -----

timer_on(1)

A = (1..fa)                 // 1 x fa
B = (1..fb)*10              // 1 x fb
C = (1..fc)*100             // 1 x fc

larger = 0
for (i=1; i<=cols(A); i++) {
    for (j=1; j<=cols(B); j++) {
        for (k=1; k<=cols(C); k++) {

            larger = larger + (A[1,i] + B[1,j] + C[1,k] > 7)

        }   
    }
}

larger

timer_off(1)


//----- Method 2 (ec27) -----

timer_on(2)

A = (1..fa)                 // 1 x fa
B = (1..fb)*10              // 1 x fb
C = (1..fc)*100             // 1 x fc

larger = 0
for (i=1; i<=cols(A); i++) {
    for (j=1; j<=cols(B); j++) {
        for (k=1; k<=cols(C); k++) {

            placebo = A[1,i] + B[1,j] + C[1,k]
            if (placebo > 7) larger = larger + 1

        }   
    }
}

larger 

timer_off(2)

timer()

end