轉自:http://blog.sina.com.cn/s/blog_9e67285801010ttn.html
網上關於bsxfun的東西不多,今天需要看到一個,由於原博文插入的圖片顯示不出來,於是筆者大發善心進行了contrl+V 以及alt+ctrl+A的操作,供大家交流學習。
bsxfun是一個matlab自版本R2007a來就提供的一個函數,作用是”applies an element-by-element binary operation to arrays a and b, with singleton expansion enabled.”
舉個例子。假設我們有一列向量和一行向量。
a = randn(3,1), b = randn(1,3)
a = -0.2453 -0.2766 -0.1913
b = 0.6062 0.5655 0.9057
我們可以很簡單的使用matlab的外乘c=a*b
來得到,如圖
但如果我們想用”外加”呢?也就是說把上式求解過程中的乘號換做加號?
這時我們可以用c=bsxfun(@plus,a,b)
來實現。
bsxfun的執行是這樣的,如果a和b的大小相同,那麼c=a+b. 但如果有某維不同,且a或b必須有一個在這一維的維數爲1, 那麼bsxfun就將少的這個虛擬的複製一些來使與多的維數一樣。在我們這裏,b的第一維只有1(只一行),所以bsxfun將b複製3次形成一個3×3的矩陣,同樣也將a複製成3×3的矩陣。這個等價於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是顯式的複製,當然帶來內存的消耗。而bsxfun是虛擬的複製,實際上通過for來實現,等效於for(i=1:3),for(j=1:3),c(i,j)=a(i)+b(j);end,end
。但bsxfun不會有使用matlab的for所帶來額外時間。
實際驗證下這三種方式
>> 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
從計算時間上來說前兩種實現差不多,遠高於for的實現。但如果數據很大,第二種實現可能會有內存上的問題。所以bsxfun最好。
這裏@plus是加法的函數數柄,相應的有減法@minus, 乘法@times, 左右除等,具體可見 doc bsxfun.
下面看一個更爲實際的情況。假設我們有數據A和B, 每行是一個樣本,每列是一個特徵。我們要計算高斯核,既:
k(||x-xc||)=exp{- ||x-xc||^2/(2*σ)^2) } 其中xc爲核函數中心,σ爲函數的寬度參數,控制了函數的徑向作用範圍。
當然可以用雙重for實現(如果第一直覺是用三重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, 運行時間爲88秒。 考慮下面向量化後的版本:
sA = (sum(A.^2, 2));
sB = (sum(B.^2, 2));
K2 = exp(bsxfun(@minus,bsxfun(@minus,2*A*B', sA), sB')/beta);
使用同樣數據,運行時間僅0.85秒,加速超過100倍。
如要判斷兩者結果是不是一樣,可以如下 assert(all(all(abs(K1-K2)<1e-12)))
C = bsxfun(fun,A,B) appliesthe element-by-element binary operation specified by the functionhandlefun to arrays A and B,with singleton expansion enabled.fun can be oneof the following built-in functions:
@plus |
Plus |
@minus |
Minus |
@times |
Array multiply |
@rdivide |
Right array divide |
@ldivide |
Left array divide |
@power |
Array power |
@max |
Binary maximum |
@min |
Binary minimum |
@rem |
Remainder after division |
@mod |
Modulus after division |
@atan2 |
Four quadrant inverse tangent |
@hypot |
Square root of sum of squares |
@eq |
Equal |
@ne |
Not equal |
@lt |
Less than |
@le |
Less than or equal to |
@gt |
Greater than |
@ge |
Greater than or equal to |
@and |
Element-wise logical AND |
@or |
Element-wise logical OR |
@xor |
Logical exclusive OR |