我有一个mxn
矩阵A,有非常小或非常大的元素。例如:
A = -1e4*randn(10,20);
我想创建一个大小相同的新矩阵C,如下所示:
首先,定义一个矩阵B,其元素是A:
元素的指数B = exp(A)
然后,定义矩阵C,使得C的每列与B的对应列成比例,并且C的每列的总和等于1.换句话说,如果我们采用B的元素并且除以它通过相同列的所有元素的总和,然后我们获得C:
的相应元素C = bsxfun(@rdivide,B,sum(B));
在数学上:
显然,C的所有元素都在0和1之间。但是,当使用以下代码进行计算时,获得的矩阵包含许多NaN:
A = -1e4*randn(10,20);
B = exp(A);
C = bsxfun(@rdivide,B,sum(B));
sum(sum(isnan(ee)))
我希望有人可以建议一种方法来克服这个问题。非常感谢你提前。
更新:请注意,目标是矩阵C.我定义矩阵B仅用于解释目的,我们可能不必计算它。 (我们实际上不应该。因为@ EJG89指出B只包含Inf和0)。
更新2:感谢@ EJG89提供了Log Sum of Exponentials technique的链接,这可能很有用。我正在努力为我的问题寻找类似的分析技巧。
更新3:正如@Dan和@ EJG89所建议的那样,我们可以用常数减去每一列,以获得合理范围内的新矩阵。显然,我们有
对于任何常数C.我们可以选择C作为每列的最大值:
(a_ {max,j}是第j列的最大值),然后
我觉得这个选择可能会给出非常好的近似值,但我不知道它有多好:|
新代码是:
A = bsxfun(@minus,A,max(A));
B = exp(A);
C = bsxfun(@rdivide,B,sum(B));
答案 0 :(得分:3)
您想将 A 调整为一些新的 A' ,以便 e A = Ce A&# 39; 其中 C 是一个常数(远小于1)。换句话说,您正在寻找一些 k ,以便 ke A 足够小,不会违反ndoublemax
或{ {1}}。但是我们希望将 k 应用于 A ,因此我们需要将它放入指数中。 k = e ln(k) 和e ln(k) .e A = e < sup> A + ln(k) 因此,如果我们从eps
加上或减去一个数字, e A 会按比例生效。或 A&#39; = A + ln(k)
不幸的是,我认为你的范围太大,无法让任何 ln(k)阻止你超越Matlab双打的限制。如果你添加一个大数字,你将A
的所有B
等于inf
,如果你减去一个大数字,你将得到B
的全部等于零。
所以你需要找到一些同时使用大量数字和分钟数的方法。
答案 1 :(得分:0)
直接方法是不可能的。
A = -1e4*randn(10,20);
B = exp(A);
问题是B已经产生Inf或0。
让分裂不可能归还南楠。
ndoublemax = realmax
nsinglemax = realmax('single')
ndoublemin = realmin
nsinglemin = realmin('single')
得到以下特性:
ndoublemax =
1.7977e + 308
nsinglemax =
3.4028e + 038
ndoublemin =
2.2251e-308
nsinglemin =
1.1755e-038
所以B的值明显超过了这些值。
可以通过以下方式重写指数来进行近似: http://lingpipe-blog.com/2009/06/25/log-sum-of-exponentials/
首先改写为: log(Cij)= log(exp(Aij)/ sumk(exp(A(kj))))
log(Cij)= Aij - log(sumk(exp(A(kj)))
其中最后一项可以近似为: m = maxk(A(kj))
log(sumk(exp(A(kj)))= m + log(exp(A(kj)-m))
这导致MatLab能够处理更小的值,即可以说是标准化。尽管如此,仍然没有确切的答案,因为有些值会变为零,从而消除了它们有时的重要贡献
亲切的问候,
Ernst Jan
答案 2 :(得分:0)
在讨论了@ EJG89之后,您可以使用最大可表示数字替换无限值,然后将eps
添加到分母中的所有数字。这样就避免了Inf
。
A = -1e4*randn(10,20);
B = exp(A);
B(isinf(B)) = realmax;
C = bsxfun(@rdivide,B,sum(B)+eps);
sum(isnan(C(:)))
答案 3 :(得分:0)
一种方法可能是采用符号计算:
A = -1e4*randn(10,20);
S = sym(A,'d'); %// convert to symbolic
C = exp(S)./repmat(sum(exp(S)),size(S,1),1);
结果C
以符号形式给出。例如,第一列将类似于
>> C(:,1)
ans =
2.9347694526167482187885232843876*10^(-790)
1.548257079197982942994953632259*10^(-10497)
8.4257350773369612716806306890481*10^(-6390)
3.1937456016712092927990884814437*10^(-7937)
4.0377045095817442881784227420794*10^(-4076)
1.0
3.3704875581881026436375125643672*10^(-6482)
8.9221015470879963245101895439354*10^(-12246)
9.4968643813486260650483647051531*10^(-11252)
1.8777491443104052522832960625121*10^(-11084)
但请注意,即使使用符号计算,最大项也是1,实际上它(稍微)更小。当然,如果你转换为double,你只能获得0或1个值:
>> Cd = eval(C);
>> Cd(:,1)
ans =
0
0
0
0
0
1
0
0
0
0