具体来说,我试图从内核函数创建一个内核矩阵,该函数将向量作为输入并生成标量作为输出。然后,核矩阵是每对矢量的这种输出的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
答案 0 :(得分:1)
bsxfun
可以与 N - 维数组一起使用,它将扩展它们的单例维度。但它在元素方面有效。如果你想要一个功能来做一些"聚合"沿着行的操作,如在您的示例中,bsxfun
只能执行元素部分(使用单例扩展)。然后,您需要补充其他一些聚合函数以获得最终结果。
对于您示例中的特定情况,您想要的函数可以分解为逐元素减法(这是bsxfun
输入的位置),然后沿行(聚合部分)求和,然后逐元素求平方根。要使用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