我正在做一个涉及科学计算的项目。以下是我在一些实验后得到的三个变量及其值。
还有一个包含三个未知数的等式a
,b
和c
:
x=(a+0.98)/y+(b+0.7)/z+c
如何使用上述方法获取a,b,c
的值?这在MATLAB中是否可行?
答案 0 :(得分:2)
这听起来像回归问题。假设测量中无法解释的误差是高斯分布的,您可以通过least squares找到参数。基本上,你必须重写方程,以便你得到ma + nb + oc = p
的形式,然后你有6个方程有3个未知数(a, b, c
),这些参数可以通过优化至少找到广场。因此,通过一些代数,我们得到:
za + yb + yzc = xyz - 0.98z - 0.7z
因此,m = z, n = y, o = yz, p = xyz - 0.98z - 0.7z
。我会把这个留给你作为练习来验证我的代数是正确的。然后,您可以形成矩阵方程:
Ax = d
我们有6个方程,我们想要求x
x = [a b c]^{T}
。要解决x
,您可以使用所谓的pseudoinverse来检索参数,以最大限度地减少真实输出与这些参数生成的输出之间的误差(如果您要使用相同的输入数据。
换句话说:
x = A^{+}d
A^{+}
是矩阵A
的伪逆,矩阵向量乘以向量d
。
为了将我们的想法放入代码中,我们将定义输入数据,形成A
矩阵和d
向量,其中每个行之间共享的行都是一个等式,然后使用伪逆来查找我们的参数。您可以使用ldivide (\)
运算符来完成工作:
%// Define x y and z
x = [9.98; 8.3; 8.0; 7; 1; 12.87];
y = [7.9; 7.5; 7.4; 6.09; 0.9; 11.23];
z = [7.1; 5.6; 5.9; 5.8; -1.8; 10.8];
%// Define A matrix
A = [z y y.*z];
%// Define d vector
d = x.*y.*z - 0.98*z - 0.7*z;
%// Find parameters via least-squares
params = A\d;
params
存储参数a
,b
和c
,我们得到:
params =
-37.7383
-37.4008
19.5625
如果您想仔细检查值的接近程度,可以在帖子中使用上面的表达式,并与x
中的每个值进行比较:
a = params(1); b = params(2); c = params(3);
out = (a+0.98)./y+(b+0.7)./z+c;
disp([x out])
9.9800 9.7404
8.3000 8.1077
8.0000 8.3747
7.0000 7.1989
1.0000 -0.8908
12.8700 12.8910
你可以看到它并不完全接近,但你得到的参数在最小二乘错误意义上是最好的。
您可以看到一些预测值(输出中的右列)比其他值更多。这是因为我们在您的数据中使用所有点来查找相应的模型。一种用于最小化误差并增加模型估计的稳健性的技术是使用称为RANSAC或 RAN dom SA mple C的东西强> onsensus。 RANSAC背后的基本方法是,对于一定数量的迭代,您可以获取数据并随机抽样查找模型所需的最少点数。找到此模型后,如果要使用这些参数来描述数据,则会发现总体错误。你随机选择点,找到你的模型,找到错误和产生最小误差的迭代将是你保持定义整体模型的参数。
如上所示,我们可以定义的一个错误是真实x
点与预测x
点之间的绝对差值之和。还有许多其他措施,例如平方误差的总和,但现在让我们坚持使用简单的东西。如果你看一下上面的公式,我们需要至少三个方程式来定义a
,b
和c
,对于每一个迭代,我们随机选择三个点无需替换我可能会添加,找到我们的模型,确定错误,并继续迭代并找到误差最小的参数。
因此,您可以像这样编写RANSAC算法:
%// Define cost and number of iterations
cost = Inf;
iterations = 50;
%// Set seed for reproducibility
rng(123);
%// Define x y and z
x = [9.98; 8.3; 8.0; 7; 1; 12.87];
y = [7.9; 7.5; 7.4; 6.09; 0.9; 11.23];
z = [7.1; 5.6; 5.9; 5.8; -1.8; 10.8];
for idx = 1 : iterations
%// Determine where we would need to sample
ind = randperm(numel(x), 3);
xs = x(ind); ys = y(ind); zs = z(ind); %// Sample
%// Define A matrix
A = [zs ys ys.*zs];
%// Define d vector
d = xs.*ys.*zs - 0.98*zs - 0.7*zs;
%// Find parameters via least-squares
params = A\d;
%// Determine error
a = params(1); b = params(2); c = params(3);
out = (a+0.98)./y+(b+0.7)./z+c;
err = sum(abs(x - out));
%// If error produced is less than current error
%// then save parameters
if err < cost
cost = err;
final_params = params;
end
end
当我运行上面的代码时,我得到了我的参数:
final_params =
-38.1519
-39.1988
19.7472
将此与我们的x
相比较,我们得到:
a = final_params(1); b = final_params(2); c = final_params(3);
out = (a+0.98)./y+(b+0.7)./z+c;
disp([x out])
9.9800 9.6196
8.3000 7.9162
8.0000 8.1988
7.0000 7.0057
1.0000 -0.1667
12.8700 12.8725
正如您所看到的,值得到了改善 - 特别是第四和第六点......并将其与之前的版本进行比较:
9.9800 9.7404
8.3000 8.1077
8.0000 8.3747
7.0000 7.1989
1.0000 -0.8908
12.8700 12.8910
您可以看到第二个值比之前版本更差,但其他数字更接近真实值。
玩得开心!