%將訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)都去中心化
X = traindata;
label = traingnd;
m = mean(X);
X_zm = bsxfun(@minus, X, m);
traindata_zm = bsxfun(@minus, traindata, m);
testdata_zm = bsxfun(@minus, testdata, m);

matlab函數(shù) bsxfun淺談(轉(zhuǎn)載)
http://blog.sina.com.cn/s/blog_9e67285801010ttn.html

網(wǎng)上關(guān)于bsxfun的東西不多,今天需要看到一個(gè),由于原博文插入的圖片顯示不出來,于是筆者大發(fā)善心進(jìn)行了contrl+V 以及alt+ctrl+A的操作,供大家交流學(xué)習(xí)。

 

bsxfun是一個(gè)matlab自版本R2007a來就提供的一個(gè)函數(shù),作用是”applies an element-by-element binary operation to arrays a and b, with singleton expansion enabled.”

舉個(gè)例子。假設(shè)我們有一列向量和一行向量。

a = randn(3,1), b = randn(1,3) a = -0.2453 -0.2766 -0.1913 b = 0.6062 0.5655 0.9057

我們可以很簡(jiǎn)單的使用matlab的外乘c=a*b來得到,如圖 bsxfun淺談(轉(zhuǎn)載)" o:button="t" target='"_blank"' o:spid="_x0000_i1025">bsxfun淺談(轉(zhuǎn)載)" src="file:///C:\Users\jie\AppData\Local\Temp\msohtmlclip1\01\clip_image001.jpg">
但如果我們想用外加呢?也就是說把上式求解過程中的乘號(hào)換做加號(hào)?

這時(shí)我們可以用c=bsxfun(@plus,a,b)來實(shí)現(xiàn)。

bsxfun的執(zhí)行是這樣的,如果ab的大小相同,那么c=a+b. 但如果有某維不同,且ab必須有一個(gè)在這一維的維數(shù)為1, 那么bsxfun就將少的這個(gè)虛擬的復(fù)制一些來使與多的維數(shù)一樣。在我們這里,b的第一維只有1(只一行),所以bsxfunb復(fù)制3次形成一個(gè)3×3的矩陣,同樣也將a復(fù)制成3×3的矩陣。這個(gè)等價(jià)于c=repmat(a,1,3)+repmat(b,3,1)。這里

repmat(a,1,3) ans = -0.2453 -0.2453 -0.2453 -0.2766 -0.2766 -0.2766 -0.1913 -0.1913 -0.1913


repmat
是顯式的復(fù)制,當(dāng)然帶來內(nèi)存的消耗。而bsxfun是虛擬的復(fù)制,實(shí)際上通過for來實(shí)現(xiàn),等效于for(i=1:3),for(j=1:3),c(i,j)=a(i)+b(j);end,end。但bsxfun不會(huì)有使用matlabfor所帶來額外時(shí)間。實(shí)際驗(yàn)證下這三種方式


>> c = bsxfun(@plus,a,b) c = 0.3609 0.3202 0.6604 0.3296 0.2889 0.6291 0.4149 0.3742 0.7144 >> c = repmat(a,1,3)+repmat(b,3,1) c = 0.3609 0.3202 0.6604 0.3296 0.2889 0.6291 0.4149 0.3742 0.7144 >> for(i=1:3),for(j=1:3),c(i,j)=a(i)+b(j);end,end,c c = 0.3609 0.3202 0.6604 0.3296 0.2889 0.6291 0.4149 0.3742 0.7144


從計(jì)算時(shí)間上來說前兩種實(shí)現(xiàn)差不多,遠(yuǎn)高于for的實(shí)現(xiàn)。但如果數(shù)據(jù)很大,第二種實(shí)現(xiàn)可能會(huì)有內(nèi)存上的問題。所以bsxfun最好。


下面看一個(gè)更為實(shí)際的情況。假設(shè)我們有數(shù)據(jù)A和B, 每行是一個(gè)樣本,每列是一個(gè)特征。我們要計(jì)算高斯核,既:





這里@plus是加法的函數(shù)數(shù)柄,相應(yīng)的有減法@minus, 乘法@times, 左右除等,具體可見 doc bsxfun.


 
k(||x-xc||)=exp{- ||x-xc||^2/(2*σ)^2) } 其中xc為核函數(shù)中心,σ為函數(shù)的寬度參數(shù) , 控制了函數(shù)的徑向作用范圍。


當(dāng)然可以用雙重for實(shí)現(xiàn)(如果第一直覺是用三重for的話…)。


K1 = zeros(size(A,1),size(B,1)); for i = 1 : size(A,1) for j = 1 : size(B,1) K1(i,j) = exp(-sum((A(i,:)-B(j,:)).^2)/beta); end end


使用2,000×1,000大小的A和B, 運(yùn)行時(shí)間為88秒。
考慮下面向量化后的版本:

sA = (sum(A.^2, 2)); sB = (sum(B.^2, 2)); K2 = exp(bsxfun(@minus,bsxfun(@minus,2*A*B', sA), sB')/beta);


使用同樣數(shù)據(jù),運(yùn)行時(shí)間僅0.85秒,加速超過100倍。
如要判斷兩者結(jié)果是不是一樣,可以如下

assert(all(all(abs(K1-K2)<1e-12)))