matlab 同时处理大量数字和分钟数字

fiei3ece  于 2023-10-23  发布在  Matlab
关注(0)|答案(4)|浏览(191)

我有一个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));
qmb5sa22

qmb5sa221#

你想把 A 调整为新的 A',使得 eA = CeA',其中 C 是一个常数(远小于1)。换句话说,你要找一个 k,使得 k.eA 足够小,不会突破ndoublemaxeps。但是我们想把 k 应用到 A 上,所以我们需要把它代入指数。k = eln(k) 和eln(k).eA =**eA + ln(k)**因此,如果我们从A中增加或减少一个数,eA 会按比例影响。或 A' = A + ln(k)
不幸的是,我认为你的范围对于任何 ln(k) 来说都太大了,无法阻止你违反Matlab双精度的限制。如果你加上一个大的数字,你会得到所有的B等于inf,如果你减去一个大的数字,你会得到所有的B等于零。
所以你需要找到一些方法来同时处理大量的数字和分钟的数字。

lyfkaqu1

lyfkaqu12#

在@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(:)))
cnjp1d6j

cnjp1d6j3#

一种方法可以是诉诸符号计算:

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
jvlzgdj9

jvlzgdj94#

直接的方法是不可能的。

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的价值显然超过了那些价值。
可以通过重写指数using this blog post来进行近似
所以首先重写为: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能够处理更小的值,即可以说是正常化。但仍然没有确切的答案,因为有些值变为零,消除了它们有时的重要贡献。

相关问题