数学公式到编程代码的转换真的是一模一样吗?


最近一直在看高斯混合模型的内容,其中不乏要对里边出现的数学公式进行画图表示。所有的参考给出的数学公式很详细,但是当你真的想要将这个思想要用编程展现出来的话,或许还需要参看一下我的这篇文章。因为在实现的时候我也是发现了一些问题,例如有的编程代码就是直接对于数学公式的简单写法,但是有些较为复杂的公式,如果你再使用这种方法复刻的话,或许出现的结果会不尽人意。
为了探究其原因,遂写了此篇博客。

1.1 公式到代码–直接代换

在我在尝试画出一维高斯分布图像的时候,根据其如下公式:
f(x)=12πδe(xμ)22δ2 f(x)= \frac{1}{\sqrt{2 \pi}\cdot \delta}\cdot e^{-\frac{{(x-\mu)}^2}{2\delta^2}}
我们在matlab进行绘制的时候,完全可以实现,以下为我实现的代码

clc;
clear all;
x=1:1:100;
mu=50;%设置均值
sigma=6;%设置sigma
y=exp(-(x-mu).^2/(2*sigma.^2))/(sigma*sqrt(2*pi));%定义表达式
plot(x,y);%绘画表达式

其结果如下:
在这里插入图片描述

1.2 公式到代码–无法直接代换

但是如果当我们要去画二维高斯分布的时候就会出现问题,下面就是多维高斯分布的表达式,如果只表示二维的话,我们令D=2即可。
N(Xμ,Σ)=1(2π)D2Σ12e(Xμ)TΣ1(Xμ)2 N(\vec{X}\mid\vec{\mu},{\Sigma})=\frac{1}{{(2\pi)}^{\frac{D}{2}}\cdot {\mid \Sigma\mid}^{\frac{1}{2}}}\cdot e^{-\frac{({\vec{X}-\vec{\mu})}^T\cdot{\Sigma^{-1}}\cdot{({\vec{X}-\vec{\mu})}}}{2}}
\qquad式中各个参数代表的意思如下:

  1. X\vec{X}表示维度为D的向量,
  2. μ\vec{\mu}是由多个变量x1,x2,x3xnx_1,x_2,x_3\cdot\cdot\cdot x_n各自的均值uiu_i组成的向量,
  3. Σ\Sigma代表所有向量的协方差矩阵,是一个n维n列的矩阵,
  4. Σ1\Sigma^{-1}代表协方差矩阵的逆,也是一个n维n列的矩阵。

于是按照这个理解,我就尝试编写了一下代码,但是结果却不是我想要得到的。
以下就是我的代码:

%使用原始矩阵的方式画图---很明显不是我们需要的数据
clc;
clear all;
X=(0:.1:5);
Y=(0:.1:5);
%设置Sigma
sigma=[1 0;
    0 1];
%设置均值向量
mu=[2.5 3];
A=[X;Y];
for i=1:length(X)
    A(:,i)=A(:,i)-mu';
end
%计算sigma的逆
inv1=inv(sigma);%求取协方差的逆
%开始书写公式
A=A'*inv1*A;
A=-A/(2);
A=exp(A);
%求取协方差的行列式
B=det(inv1);
Z=A/(2*pi*sqrt(B));
% 显示高斯函数的三维曲面
csn = mapminmax(Z);%归一化数值
figure, surf(X, Y, csn);axis tight

得到的效果不尽人意,如下所示:
在这里插入图片描述
于是开始尝试思考一下是哪里出了问题,就对上边的公式进行了进一步的推导,具体步骤可以参考我的另一篇博客,这里列出参考网址:多维高斯分布
最后得到一个公式:
f(x1,x2)=12πδ1δ2e12δ12δ22[δ22(x1μ1)2+δ12(x2μ2)2] f(x_1,x_2)=\frac{1}{{2 \pi}\delta_1 \delta_2}\cdot e^{-\frac{1}{2\delta_1^2\delta_2^2}\cdot[ \delta_2^2\cdot(x_1-\mu_1)^2+\delta_1^2\cdot(x_2-\mu_2)^2]}
于是我就尝试着看看是不是这样可以画出来,于是就根据这个公式写了一通代码,如下所示:


%原始方式:也是最直接的方式

% 先限定三维图中的x,y轴坐标范围
X = 0 : .1 : 5;
Y = 0 : .1 : 5;
 
% 标准差,均值定义
sigma1 = 1;
sigma2=1;
mu1=2.5;
mu2=3;
%for 循环写入值
Z = zeros( 51, 51 );
for row = 1 : 1 : 51
    for col = 1 : 1 : 51
        %Z( row, col ) = [sigma2^2*(X(row) - mu1 ).^2 + sigma1^2*( Y(col) - mu2 ).^2]; % 均值(25, 25)
        %尝试更换为矩阵乘法方式
        Z( row, col )=[sigma2^2 sigma1^2]*[(X(row) - mu1 ).^2;( Y(col) - mu2 ).^2];
        %经过测试,二者皆可。
    end
end
Z = -Z / ( 2 * sigma1^2*sigma2^2 );
 
Z = exp(Z) / ( 2 * pi * sigma1*sigma2 );
 
% 显示高斯函数的三维曲面
figure, surf(X, Y, Z);
%plot3(X,Y,Z)

经过测试,结果竟然可以,以下则是其结果:
在这里插入图片描述

1.3 原因探究

在上一节的问题中也给了我一个很大的疑问,同样的公式为啥第二次继续往前推了几步就可以了。于是抱着这个疑问,我又重新观察了一下,发现,其实上述第二个编程在理论上上是存在问题的,问题就是本来是一个向量的,结果后来在真正编程的时候变成了一个固定的数来代替。下面是我做的详细的探究。因为问题主要出在e指数的部分,所以此处我仅探究这一部分。

1.3.1 矩阵形式推导

因为此处我的程序用的就是51个样点,于是我就使用了里边的51来代替通常所用的n,其具体的推导如下:
(Xμ)TΣ1(Xμ)=[x(1)μ1y(1)μ2x(2)μ1y(2)μ2x(51)μ1y(51)μ2]1δ12δ22[δ2200δ12][x(1)μ1x(2)μ1x(51)μ1y(1)μ2y(2)μ2y(51)μ2]=1δ12δ22[δ22(x(1)μ1)δ12(y(1)μ2)δ22(x(2)μ1)δ12(y(2)μ2)δ22(x(51)μ1)δ12(y(51)μ2)][x(1)μ1x(2)μ1x(51)μ1y(1)μ2y(2)μ2y(51)μ2]=1δ12δ22[δ22(x(1)μ1)2+δ12(y(1)μ2)2δ22(x(1)μ1)(x(2)μ1)+δ12(y(1)μ2)(y(2)μ2)δ22(x(1)μ1)(x(51)μ1)+δ12(y(1)μ2)(y(51)μ2)δ22(x(2)μ1)(x(1)μ1)+δ12(y(2)μ2)(y(1)μ2)δ22(x(2)μ1)2+δ12(y(2)μ2)2δ22(x(2)μ1)(x(51)μ1)+δ12(y(2)μ2)(y(51)μ2)δ22(x(51)μ1)(x(1)μ1)+δ12(y(51)μ2)(y(1)μ2)δ22(x(51)μ1)(x(2)μ1)+δ12(y(51)μ2)(y(2)μ2)δ22(x(51)μ1)2+δ12(y(51)μ2)2] ({\vec{X}-\vec{\mu})}^T\cdot{\Sigma^{-1}}\cdot{({\vec{X}-\vec{\mu})}}\\\qquad\\\qquad =\left[ \begin{matrix} x(1)-\mu_1 & y(1)-\mu_2\\\\ x(2)-\mu_1 & y(2)-\mu_2 \\\cdots & \cdots\\x(51)-\mu_1 & y(51)-\mu_2\end{matrix} \right] \cdot\frac{1}{\delta_1^2\delta_2^2}\left[ \begin{matrix} \delta_{2} ^2& 0\\ \\0& \delta_{1}^2 \end{matrix} \right]\cdot\left[ \begin{matrix} x(1)-\mu_1& x(2)-\mu_1&\cdots&x(51)-\mu_1\\ \\ y(1)-\mu_2& y(2)-\mu_2&\cdots&y(51)-\mu_2 \end{matrix} \right] \\\qquad\\\qquad =\frac{1}{\delta_1^2\delta_2^2}\cdot \left[ \begin{matrix} \delta_2^2\cdot(x(1)-\mu_1) & \delta_1^2\cdot(y(1)-\mu_2)\\ \\ \delta_2^2\cdot(x(2)-\mu_1) & \delta_1^2\cdot(y(2)-\mu_2) \\\cdots & \cdots\\\delta_2^2\cdot(x(51)-\mu_1) & \delta_1^2\cdot(y(51)-\mu_2)\end{matrix} \right] \left[ \begin{matrix} x(1)-\mu_1& x(2)-\mu_1&\cdots&x(51)-\mu_1\\ \\ y(1)-\mu_2& y(2)-\mu_2&\cdots&y(51)-\mu_2 \end{matrix} \right] \\\qquad\\\qquad =\frac{1}{\delta_1^2\delta_2^2}\cdot \left[ \begin{matrix} \delta_2^2\cdot(x(1)-\mu_1)^2+\delta_1^2\cdot(y(1)-\mu_2)^2& \qquad \delta_2^2\cdot(x(1)-\mu_1)(x(2)-\mu_1)+\delta_1^2\cdot(y(1)-\mu_2)(y(2)-\mu_2) & \qquad \cdots \qquad&\delta_2^2\cdot(x(1)-\mu_1)(x(51)-\mu_1)+\delta_1^2\cdot(y(1)-\mu_2)(y(51)-\mu_2) \\ \\ \delta_2^2\cdot(x(2)-\mu_1)(x(1)-\mu_1)+\delta_1^2\cdot(y(2)-\mu_2)(y(1)-\mu_2)& \qquad \delta_2^2\cdot(x(2)-\mu_1)^2+\delta_1^2\cdot(y(2)-\mu_2) ^2& \qquad \cdots \qquad&\delta_2^2\cdot(x(2)-\mu_1)(x(51)-\mu_1)+\delta_1^2\cdot(y(2)-\mu_2)(y(51)-\mu_2) \\ \cdots & \cdots& \cdots& \cdots\\ \delta_2^2\cdot(x(51)-\mu_1)(x(1)-\mu_1)+\delta_1^2\cdot(y(51)-\mu_2)(y(1)-\mu_2)& \qquad \delta_2^2\cdot(x(51)-\mu_1)(x(2)-\mu_1)+\delta_1^2\cdot(y(51)-\mu_2)(y(2)-\mu_2) & \qquad \cdots \qquad&\delta_2^2\cdot(x(51)-\mu_1)^2+\delta_1^2\cdot(y(51)-\mu_2) ^2\end{matrix} \right]
也就是说,如果我们按照
N(Xμ,Σ)=1(2π)D2Σ12e(Xμ)TΣ1(Xμ)2 N(\vec{X}\mid\vec{\mu},{\Sigma})=\frac{1}{{(2\pi)}^{\frac{D}{2}}\cdot {\mid \Sigma\mid}^{\frac{1}{2}}}\cdot e^{-\frac{({\vec{X}-\vec{\mu})}^T\cdot{\Sigma^{-1}}\cdot{({\vec{X}-\vec{\mu})}}}{2}}
这个式子编写的话,其指数内的数字因该如上所示的。

1.3.2 编程成功实现的版本推导

我们先看一下编程版本的e指数部分数据的确定函数,

Z = zeros( 51, 51 );
for row = 1 : 1 : 51
    for col = 1 : 1 : 51
        %Z( row, col ) = [sigma2^2*(X(row) - mu1 ).^2 + sigma1^2*( Y(col) - mu2 ).^2]; % 均值(25, 25)
        %尝试更换为矩阵乘法方式
        Z( row, col )=[sigma2^2 sigma1^2]*[(X(row) - mu1 ).^2;( Y(col) - mu2 ).^2];
        %经过测试,二者皆可。
    end
end

可以确定,该方式得到的数据形式将如这样所示:
=1δ12δ22[δ22(x(1)μ1)2+δ12(y(1)μ2)2δ22(x(1)μ1)2+δ12(y(2)μ2)2δ22(x(1)μ1)2+δ12(y(51)μ2)2δ22(x(2)μ1)2+δ12(y(1)μ2)2δ22(x(2)μ1)2+δ12(y(2)μ2)2δ22(x(2)μ1)2+δ12(y(51)μ2)2δ22(x(51)μ1)2+δ12(y(1)μ2)2δ22(x(51)μ1)2+δ12(y(2)μ2)2δ22(x(51)μ1)2+δ12(y(51)μ2)2] \\\qquad\\\qquad=\frac{1}{\delta_1^2\delta_2^2}\cdot\left[ \begin{matrix} \delta_2^2\cdot(x(1)-\mu_1)^2+\delta_1^2\cdot(y(1)-\mu_2)^2& \qquad \delta_2^2\cdot(x(1)-\mu_1)^2+\delta_1^2\cdot(y(2)-\mu_2) ^2& \qquad \cdots \qquad&\delta_2^2\cdot(x(1)-\mu_1)^2+\delta_1^2\cdot(y(51)-\mu_2) ^2 \\ \\ \delta_2^2\cdot(x(2)-\mu_1)^2+\delta_1^2\cdot(y(1)-\mu_2)^2& \qquad \delta_2^2\cdot(x(2)-\mu_1)^2+\delta_1^2\cdot(y(2)-\mu_2) ^2& \qquad \cdots \qquad&\delta_2^2\cdot(x(2)-\mu_1)^2+\delta_1^2\cdot(y(51)-\mu_2) ^2 \\ \\ \cdots & \cdots& \cdots& \cdots\\ \delta_2^2\cdot(x(51)-\mu_1)^2+\delta_1^2\cdot(y(1)-\mu_2)^2& \qquad \delta_2^2\cdot(x(51)-\mu_1)^2+\delta_1^2\cdot(y(2)-\mu_2) ^2& \qquad \cdots \qquad&\delta_2^2\cdot(x(51)-\mu_1)^2+\delta_1^2\cdot(y(51)-\mu_2) ^2 \\ \end{matrix} \right]
后续我们还可以对该数据的展现形式进行变形

1.3.3 二者差别

在这里我们也是可以看得出差别的,两个表现形式只有斜对角线的元素是相等的,其它的都不相等,我想也就是这里的差别导致了图像显示的不一样,但是为什么直接根据数学公式编辑的代码反而画不出我们所需要的数据呢,结果暂时我还不知道,如果大家有知道的,可以在底下留言,我们一起交流一下。

1.3.4 编程法改进

在编程中如果我们一直写for循环的话,就会导致程序的运行时间大量增加,我们不妨把上边用到的编程方法,利用数学推导的方法,将其公式化,那样我们在执行的时候也会简便一些。以下是我的推导过程:
=1δ12δ22[δ22(x(1)μ1)2+δ12(y(1)μ2)2δ22(x(1)μ1)2+δ12(y(2)μ2)2δ22(x(1)μ1)2+δ12(y(51)μ2)2δ22(x(2)μ1)2+δ12(y(1)μ2)2δ22(x(2)μ1)2+δ12(y(2)μ2)2δ22(x(2)μ1)2+δ12(y(51)μ2)2δ22(x(51)μ1)2+δ12(y(1)μ2)2δ22(x(51)μ1)2+δ12(y(2)μ2)2δ22(x(51)μ1)2+δ12(y(51)μ2)2]=[(x(1)μ1)21(x(2)μ1)21(x(51)μ1)21]Σ1[111(y(1)μ2)2(y(2)μ2)2(y(51)μ2)2] \\\qquad\\\qquad=\frac{1}{\delta_1^2\delta_2^2}\cdot\left[ \begin{matrix} \delta_2^2\cdot(x(1)-\mu_1)^2+\delta_1^2\cdot(y(1)-\mu_2)^2& \qquad \delta_2^2\cdot(x(1)-\mu_1)^2+\delta_1^2\cdot(y(2)-\mu_2) ^2& \qquad \cdots \qquad&\delta_2^2\cdot(x(1)-\mu_1)^2+\delta_1^2\cdot(y(51)-\mu_2) ^2 \\ \\ \delta_2^2\cdot(x(2)-\mu_1)^2+\delta_1^2\cdot(y(1)-\mu_2)^2& \qquad \delta_2^2\cdot(x(2)-\mu_1)^2+\delta_1^2\cdot(y(2)-\mu_2) ^2& \qquad \cdots \qquad&\delta_2^2\cdot(x(2)-\mu_1)^2+\delta_1^2\cdot(y(51)-\mu_2) ^2 \\ \\ \cdots & \cdots& \cdots& \cdots\\ \delta_2^2\cdot(x(51)-\mu_1)^2+\delta_1^2\cdot(y(1)-\mu_2)^2& \qquad \delta_2^2\cdot(x(51)-\mu_1)^2+\delta_1^2\cdot(y(2)-\mu_2) ^2& \qquad \cdots \qquad&\delta_2^2\cdot(x(51)-\mu_1)^2+\delta_1^2\cdot(y(51)-\mu_2) ^2 \\ \end{matrix} \right] \\\qquad\\\\\qquad\qquad= \left[ \begin{matrix} (x(1)-\mu_1)^2 & 1\\\\ (x(2)-\mu_1)^2 & 1 \\\cdots & \cdots\\(x(51)-\mu_1)^2 & 1\end{matrix} \right] \cdot \Sigma^{-1}\cdot\left[ \begin{matrix} 1& 1&\cdots&1\\ \\ (y(1)-\mu_2)^2& (y(2)-\mu_2)^2&\cdots&(y(51)-\mu_2)^2 \end{matrix} \right]
有了上边的矩阵方法的推导,我们即可按照这个思路,先去构造两个矩阵,然后再按照两个矩阵的乘法,简化计算。以下我将列出我的该版本的改进后的代码:

%测试修改矩阵的方法
clc;
clear all;
X=(0:.1:5);Y=(0:.1:5);
sigma=[1 0;0 1];
mu1=2.5;mu2=3;
%定义矩阵A(左矩阵)
A=zeros(length(X),2);
for i=1:length(X)
    A(i,:)=[(X(i)-mu1)^2 1];
end
%定义矩阵B(右矩阵)
B=zeros(2,length(X));
for i=1:length(X)
    B(:,i)=[1;(Y(i)-mu2)^2];
end
%计算sigma的逆
inv1=inv(sigma);
%开始书写公式
Z=A*inv1*B;
Z=-Z/(2);
Z=exp(Z);
%求取协方差的行列式
D=det(inv1);

Z=Z/(2*pi*sqrt(D));
% 显示高斯函数的三维曲面
figure, surf(X, Y, Z);

运行该程序即可得到我们刚刚的二维高斯分布函数:
在这里插入图片描述

2.心得体会

1.推导了一遍,并且对之前的代码进行了改进,但是目前还是存在问题,就是为什么按照数学公式来进行画图是不可以的,或者说我现在还没真正发现问题所在,所以写了这一篇博客,只希望在得到灵感的时候可以迅速找到问题的结症。
2.脚踏实地,一步步推导,慢慢来比较快~~,加油,奥里给!!!
3.不要怕麻烦,解决麻烦的过程才是真正成长的过程!

3.参考地址

多维高斯分布

发布了36 篇原创文章 · 获赞 31 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览