【轉(zhuǎn)載】讓你的MATLAB運行效率更快一些吧蓖乘!

轉(zhuǎn)自 https://www.digquant.com.cn/forum.php?mod=viewthread&tid=258

一酒朵、速度

1.1 For-循環(huán)

1、改變算法,多用矩陣運算(尤其是矩陣乘法),盡量減少for循環(huán);

2勒叠、減少for循環(huán)中的函數(shù)調(diào)用;

傳統(tǒng)觀點認為for-loop是影響性能的致命環(huán)節(jié)膏孟,讓我們來對此驗證:

  1. tic
  2. toc

Elapsed time is 0.000239 seconds.

  1. tic
  2. toc
  3. for i=1:1000000
  4. end

Elapsed time is 0.000050 seconds.

從上面的實驗結(jié)果可以得出以下結(jié)論:

1眯分、tic/toc語句的時間開銷可以忽略不計
2、for-loop語句本身的時間開銷也非常小柒桑,關(guān)鍵的影響效率的地方不在于循環(huán)本身弊决,而是在于循環(huán)的內(nèi)部。
3魁淳、tic/toc不一定要成對出現(xiàn)飘诗,一個tic后面可以有多個toc,但需要需要重新計時的時候界逛,要再次執(zhí)行tic昆稿。
4、toc的結(jié)果可以用變量接收下來息拜,如:

  1. T=toc
  2. T(k)=toc;

接下來我們就借助for循環(huán)溉潭,分析一下其他的各個影響效率的因素净响。

內(nèi)建函數(shù)

  1. tic
  2. for i=1:1000000
  3. cos(0);
  4. end
  5. toc

Mean elapsed time is 0.032866 seconds.

m-函數(shù)

  1. tic
  2. for i=1:1000000
  3. func(i);
  4. end
  5. toc

Mean elapsed time is 0.185556 seconds.

  1. function func( ~ )
  2. end

匿名函數(shù)

  1. tic
  2. for i=1:1000000
  3. funca(i);
  4. end
  5. toc

Mean elapsed time is 0.561228 seconds.

  1. funca=@(x)'';

內(nèi)聯(lián)函數(shù)

  1. tic
  2. for i=1:1000000
  3. funci(i);
  4. end
  5. toc

Mean elapsed time is 19.5606 seconds.

  1. funci=inline('','x');
image

從上面的實驗結(jié)果可以得出以下結(jié)論:
1、內(nèi)聯(lián)函數(shù)的調(diào)用時間開銷最小喳瓣,約為for-loop本身的10倍
2馋贤、m-函數(shù)的調(diào)用時間開銷約為內(nèi)聯(lián)函數(shù)的6倍,約為for-loop本身的60倍
3畏陕、匿名函數(shù)的調(diào)用時間開銷約為m-函數(shù)的3倍配乓,約為for-loop本身的187倍
4、內(nèi)聯(lián)函數(shù)的調(diào)用時間開銷過大惠毁,盡量不要在循環(huán)中使用
5犹芹、另外MEX-函數(shù)的調(diào)用時間開銷,理應(yīng)介于內(nèi)聯(lián)函數(shù)和m-函數(shù)之間

矩陣索引

  1. tic
  2. A=zeros(1000000,1);
  3. for i=1:1000000
  4. A(i)=i;
  5. end
  6. toc

Mean elapsed time is 0.007592 seconds.

  1. tic
  2. A=zeros(1000000,1);
  3. for i=1:1000000
  4. A(i,1)=i;
  5. end
  6. toc

Mean elapsed time is 0.007954 seconds.

  1. tic
  2. A=zeros(1000000,1);
  3. for i=1:1000000
  4. A(i:i,1)=i;
  5. end
  6. toc

Mean elapsed time is 0.663598 seconds.

  1. tic
  2. A=zeros(1000000,1);
  3. for i=1:1000000
  4. A(i,:)=i;
  5. end
  6. toc

Mean elapsed time is 0.273345 seconds.

  1. tic
  2. A=zeros(1000000,1);
  3. for i=1:1000000
  4. A(i,1:1)=i;
  5. end
  6. toc

Mean elapsed time is 0.730042 seconds.

  1. tic
  2. A=zeros(1000000,1);
  3. for i=1:1000000
  4. A(i:i,1:1)=i;
  5. end
  6. toc

Mean elapsed time is 1.00852 seconds.

image

二鞠绰、內(nèi)存

2.1 內(nèi)存分配

  1. tic
  2. A=zeros(1000000,1);
  3. for i=1:1000000
  4. A(i)=i;
  5. end
  6. toc

Mean elapsed time is 0.009025 seconds.

  1. tic
  2. % A=zeros(1000000,1);
  3. for i=1:1000000
  4. A(i)=i;
  5. end
  6. toc

Mean elapsed time > 20 minutes.

因此羽莺,如果不預(yù)先分配好內(nèi)存,將會大大增加仿真時間洞豁,拖慢執(zhí)行效率。

所幸的是荒给,由于這個現(xiàn)象的重要性丈挟,Matlab的編輯器能夠發(fā)現(xiàn)并提示這個問題,會用紅的波浪線~標記出來志电。

三曙咽、向量化

  1. N=0:0.1:1000;
  2. for i=0:10000
  3. y(i)=cos(N(i));
  4. end

向量化:

  1. N=0:0.1:1000;
  2. y=cos(N);

MATLAB向量化函數(shù)
accumarray函數(shù)
arrayfun函數(shù)
bsxfun函數(shù)
cellfun函數(shù)
spfun函數(shù)

3.1 accumarray函數(shù)

  1. A = accumarray(subs,val)
  2. A = accumarray(subs,val,sz)
  3. A = accumarray(subs,val,sz,fun)
  4. A = accumarray(subs,val,sz,fun,fillval)
  5. A = ccumarray(subs,val,sz,fun,fillval,issparse)
  1. val = 101:105;
  2. subs = [1; 2; 4; 2; 4]
  3. A = accumarray(subs, val)

A =

101
206
0
208

subs =
1 1 1
2 1 2
2 3 2
2 1 2
2 3 2

val =
101
102
103
104
105

1挑辆、val的元素個數(shù)與subs的行數(shù)是一致的例朱。

2、A = accumarray(subs, val)的實現(xiàn)過程分成2步鱼蝉。

第一步
是把val中的元素洒嗤,按照subs對應(yīng)行所給出的下標放到一個新的cell矩陣B中(cell是為了方便解釋,也就是說B矩陣中的每個位置可以放入多個數(shù)值)魁亦,注意渔隶,subs的值是B的下標,不是val的洁奈。舉例來說间唉,subs第一行[ 1 1 1],意思就是把val中第一個元素(val(1))放入到B(1,1利术,1)的位置呈野,依次類推,val(2)放入到B(2 1 2)印叁,val(3)放入到B(2 3 2)被冒,val(4)放入到B(2 1 2)军掂,val(5)放入到B(2 3 2)。此時姆打,可以看到B(1良姆,1,1)中有1個數(shù)(val(1))幔戏;B(2 1 2)有2個數(shù)(val(2)玛追,val(4));B(2 3 2)也有2個數(shù)(val(3)闲延,val(5))痊剖。

第二步
把B中每個單元中的數(shù)分別累加,并放入到A的對應(yīng)位置垒玲。

注:accumarray默認的是把每個單元中的數(shù)累加陆馁,因為對每個單元中的數(shù)的默認處理函數(shù)是sum『嫌可以通過A = accumarray(subs,val,[],[@fun](https://github.com/fun "@fun"))的調(diào)用格式來指定其他的處理函數(shù)叮贩,比如說mean。對指定的fun函數(shù)的要求是佛析,接受列向量輸入益老,輸出單個的數(shù)值型,字符型或邏輯型變量寸莫。A的維數(shù)與B相同捺萌,A中的元素默認為零。A的大小為max(subs(1))×max(subs(2))×max(subs(3))…

很顯然膘茎,A的維數(shù)與subs的列數(shù)相等桃纯。

  • A = accumarray(subs, val)

  • A = accumarray(subs,val,sz)

  • sz 可以用來指定A大小,但是不能小于A = accumarray(subs, val)得到的A的大小披坏。比如A = accumarray(subs, val)的到A是一個3×4的二維矩陣态坦,那么sz應(yīng)當(dāng)為一個包含2個元素的向量sz=[m1,m2] (sz向量的長度和A的維數(shù)相等),其中棒拂,m1大于等于3驮配,m2大于等于4. 但是,當(dāng)?shù)玫降腁是一個p×1的一維向量時着茸,sz=[m壮锻,1],m大于等于p涮阔。另外猜绣,sz可以賦值為空,表示由函數(shù)自動決定A的大小敬特。

  • A = accumarray(subs,val,sz,fun)
    fun可以指定專門的處理函數(shù)掰邢,默認的處理函數(shù)為sum

  • A = accumarray(subs,val,sz,fun,fillval)
    fillval指定A中元素的默認值牺陶。可以等于NaN

  • A = ccumarray(subs,val,sz,fun,fillval,issparse)
    isspares選擇A是否使用稀疏矩陣的格式

  • A = accumarray({subs1, subs2, ...}, val,...)
    {subs1, subs2, …}辣之,等同于A = accumarray(subs, val,…)掰伸,此時,subs=[subs1, subs2, …]或者=[subs1怀估;subs2狮鸭; …]

例子:
1000人,身高分布在170180cm多搀,體重在110100斤歧蕉,年齡分布在20~50歲,計算身高體重都相等的人的年齡平均值康铭。結(jié)果用矩陣來表示:行數(shù)表示身高惯退,列數(shù)表示體重,矩陣元素表示年齡的平均值从藤。

  1. height=unidrnd(10,1000,1)+170; %身高的數(shù)據(jù)
  2. weight=unidrnd(90,1000,1)+110; %體重的數(shù)據(jù)
  3. old=unidrnd(30,1000,1)+20;
  4. mo=accumarray([height,weight],old,[],@mean);
  5. %或
  6. mo=accumarray([height,weight],old,[],@mean,0,true);

3.2 arrayfun函數(shù)

arrayfun函數(shù)實現(xiàn)的是將指定的函數(shù)應(yīng)用到給定數(shù)組在內(nèi)的所有元素催跪。這樣以前不可避免的循環(huán)現(xiàn)在可以向量化了。

生成一個這樣的n×n矩陣

  1. a:a(i,j)=dblquad(@(u,v)sin(u)*sqrt(v),0,i,0,j)夷野,以n=10為例叠荠。

  2. a=zeros(10);

  3. for ii=1:10

  4. for jj=1:10

  5. a(ii,jj)=dblquad(@(u,v) sin(u)+sqrt(v),0,ii,0,jj);

  6. end

  7. End

  8. %現(xiàn)在只需要如下調(diào)用

  9. [J,I]=meshgrid(1:10);

  10. a1=arrayfun(@(ii,jj) dblquad(@(u,v) sin(u)+sqrt(v),0,ii,0,jj),I,J);

3.3 bsxfun函數(shù)

以前,當(dāng)我們想對一個矩陣A的每一列或每一行與同一個向量a進行某些操作(比較大小扫责、乘除等)時,只能用循環(huán)方法或者利用repmat函數(shù)將要操作的向量a復(fù)制成和A一樣尺寸的矩陣逃呼,進而進行操作鳖孤。從Matlab R2007a開始,有了更有效的方法抡笼,那就是bsxfun函數(shù)苏揣。
有如下矩陣:


image

向量為b=[1 2 3]T,請找出b在A矩陣列中的位置loc=[1,4]推姻。

方法1:

  1. A=[1 2 3 1;2 3 4 2;3 3 8 3]
  2. b=[1;2;3]
  3. loc = find(all(bsxfun(@eq,A,b)))
  4. %把A的每一列和b用==(@eq)來判斷平匈,找出全1的列;

方法2:

  1. loc = find(arrayfun(@(n)all(A(:,n)==b),1:4))
  2. %用arrayfun對n進行1:4的遍歷藏古;

方法3:

  1. loc =find(all(~bsxfun(@minus,A,b)))
  2. %把A的每一列和b來相減( @minus )增炭,求反后找出全1的列;

方法4:

  1. loc=find( arrayfun(@(n) isequal(A(:,n),b),1:4))
  2. %用arrayfun對n進行1:4的遍歷后用isequal函數(shù)來判斷A的每列和b是否相等拧晕;

方法5:

  1. loc=find(b'*A==sum(b.^2))
  2. %的轉(zhuǎn)置和A相乘隙姿,然后和b.^2每列的和進行比較,找到相等的;

3.4 cellfun函數(shù)

  1. A={'Hello', 'MATLAB', 'I love MATLAB', 'MATLAB is powerful', 'MATLAB is the language of technical computer'}

A={‘Hello’, ‘MATLAB’, ‘I love MATLAB’, ‘MATLAB is powerful’, ‘MATLAB is the language of technical computer’};

cellfun(@length,A)

ans =
5 6 13 18 44

3.5 spfun函數(shù)

  1. a=sparse([1 3 20 60 100],[2 20 30 60 80],1:5)

</pre>

a =

(1,2) 1
(3,20) 2
(20,30) 3
(60,60) 4
(100,80) 5

  1. sa=spfun(@(x) x.^2+1,a)

</pre>

sa =
(1,2) 2
(3,20) 5
(20,30) 10
(60,60) 17
(100,80) 26

四厂捞、函數(shù)化

  • 盡量使用內(nèi)建函數(shù)输玷,內(nèi)建函數(shù)的速度是最快的队丝。
  • m-函數(shù)的執(zhí)行效率也很高。
  • MEX-函數(shù)的執(zhí)行效率僅次于內(nèi)建函數(shù)欲鹏,將耗時的代碼寫成MEX-函數(shù),將大大提高運行速度机久。
  • 匿名函數(shù),內(nèi)聯(lián)函數(shù)赔嚎,以及一些面向?qū)ο蠓椒ū旄牵M量不要在執(zhí)行次數(shù)多的循環(huán)體內(nèi)使用。

五尽狠、預(yù)分配內(nèi)存

  1. A= zeros(1000, 1);
  2. A = int8(zeros(100, 1));
  3. A = zeros(1000, 1, 'int8');

常用的預(yù)分配內(nèi)存函數(shù):

  • zeros
  • ones
  • eye
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衔憨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子袄膏,更是在濱河造成了極大的恐慌践图,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沉馆,死亡現(xiàn)場離奇詭異码党,居然都是意外死亡,警方通過查閱死者的電腦和手機斥黑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門揖盘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锌奴,你說我怎么就攤上這事兽狭。” “怎么了鹿蜀?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵箕慧,是天一觀的道長。 經(jīng)常有香客問我茴恰,道長颠焦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任往枣,我火速辦了婚禮伐庭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘分冈。我一直安慰自己圾另,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布雕沉。 她就那樣靜靜地躺著盯捌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蘑秽。 梳的紋絲不亂的頭發(fā)上饺著,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天箫攀,我揣著相機與錄音,去河邊找鬼幼衰。 笑死靴跛,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的渡嚣。 我是一名探鬼主播梢睛,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼识椰!你這毒婦竟也來了绝葡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤腹鹉,失蹤者是張志新(化名)和其女友劉穎藏畅,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體功咒,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡愉阎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了力奋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榜旦。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖景殷,靈堂內(nèi)的尸體忽然破棺而出溅呢,到底是詐尸還是另有隱情,我是刑警寧澤猿挚,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布咐旧,位于F島的核電站,受9級特大地震影響亭饵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梁厉,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一辜羊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧词顾,春花似錦八秃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至上忍,卻和暖如春骤肛,著一層夾襖步出監(jiān)牢的瞬間纳本,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工腋颠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留繁成,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓淑玫,卻偏偏與公主長得像巾腕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子絮蒿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354