具体来说,我正在尝试从内核函数创建一个内核矩阵,该函数将向量作为输入作为输入并产生标量作为输出。然后,内核矩阵是每对向量的此类输出的2D矩阵。
对于向量输入本身为1D,我可以对此使用BSXFUN:
x = [1;2;3;4];
kerfun = @(s,t) (s-t) % some function, doesn't matter, except that it returns a scalar
kernel = bsxfun(kerfun, x, x');
输出是内核,如预期:
kernel =
0 -1 -2 -3
1 0 -1 -2
2 1 0 -1
3 2 1 0
但是,如果我将x
中的点更改为N-D向量,则此方法失败。我的问题是:是否有没有使用循环的情况来构建内核矩阵的有效方法?我尝试使用CellFun,但这似乎也没有用。谢谢。
编辑:作为预期结果的一个示例,如果我更改x
和kerfun
,则如下:
x = [1,15;23,2;13,5;4,7];
kerfun = @(s,t) norm(s-t); %some function, returns a scalar
ker = zeros(4,4);
然后用蛮力计算内核:
for i=1:size(x,1)
for j=1:size(x,1)
ker(i,j) = kerfun(x(i,:),x(j,:));
end
end
我得到:
ker =
0 25.5539 15.6205 8.5440
25.5539 0 10.4403 19.6469
15.6205 10.4403 0 9.2195
8.5440 19.6469 9.2195 0
bsxfun
可以与 n - 维数阵列一起使用,它将扩大其单元顿尺寸。但是它在元素方面起作用。如果您想要一个沿行进行某些"聚合"操作的函数,如示例中,bsxfun
只能执行元素的零件(随着Singleton扩展)。然后,您需要补充一些其他聚合功能才能获得最终结果。
对于示例中的特定情况,您想要的函数可以分解为元素的减法(这是bsxfun
进入的地方),然后沿行(聚合部分)和元素平方root总和。要用bsxfun
进行减法,您需要将x
副本的第一个维度输送到第三维。这样,第一个和第三维涵盖了两个循环中i
和j
的所有组合。
然后沿结果3D阵列的第二个维度汇总,取平方根,然后倒入矩阵结果:
ker = sqrt(permute(sum(bsxfun(@minus, x, permute(x, [3 2 1])).^2, 2), [1 3 2]));
请注意,使用bsxfun
的内置函数之一(例如minus
)比自定义功能要快。
对于x = [1,15;23,2;13,5;4,7]
,这会产生
ker =
0 25.5539 15.6205 8.5440
25.5539 0 10.4403 19.6469
15.6205 10.4403 0 9.2195
8.5440 19.6469 9.2195 0