最小二乘法学习笔记
一维数据拟合
参考自https://blog.csdn.net/shenliang1985/article/details/112327554?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2aggregatepagefirst_rank_ecpm_v1~rank_aggregation-1-112327554.pc_agg_rank_aggregation&utm_term=%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%B3%95%E7%9A%84%E5%81%8F%E5%AF%BC%E6%95%B0%E6%8E%A8%E5%AF%BC&spm=1000.2123.3001.4430
设目标一维方程为
\[Y= ax+b+ε
\]
a | 斜率 |
---|---|
b | Y的截距 |
ε | 误差 |
一维方程可得
\[ε=Y - ax - b
\]
\[Q=\sum_{i=1}^{n}{ε_i^2}=\sum_{i=1}^{n}({Y_i} -{y_i})^2 = \sum_{i=1}^{n}(Yi - ax-b)^2
\]
Q | 残差平方和 |
---|---|
ε | 差量 |
Y | 实际值 |
y | 拟合函数值 |
a | 斜率 |
b | Y的截距. |
将a,b设为变量,求Q对两个待估函数的偏导数:
\[\begin{cases}
\frac{∂Q}{∂a}=-2\sum_{i=1}^{n}(Y-a{x_i}-b){x_i}=0\\
\frac{∂Q}{∂b}=-2\sum_{i=1}^{n}(Y-a{x_i}-b)=0
\end{cases}
\]
\[a=\frac{n\sum_{i = 1}^{n}{x_i}{y_i}-\sum_{i=1}^{n}{x_i}\sum_{i = 1}^{n}{y_i}}{n\sum_{i = 1}^{n}{x_i}^2-(\sum_{i = 1}^{n}{x_i})^2}\\
b=\frac{\sum_{i = 1}^{n}{x_i}^2\sum_{i = 1}^{n}{y_i}-\sum_{i=1}^{n}{x_i}\sum_{i = 1}^{n}{x_i}{y_i}}{n\sum_{i = 1}^{n}{x_i}^2-(\sum_{i = 1}^{n}{x_i})^2}
\]
由C++实现代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int n;
vector<double>x, y;
template <typename T>
inline void read(T& x) {
x = 0;
T op = 1;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar())
if (c == '-') op = -1;
for (; c <= '9' && c >= '0'; c = getchar())
x = (x << 3) + (x << 1) + c - '0';
x *= op;
}
inline double Get_a() {
double sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0;
for (int i = 0; i < n; ++i)
sum1 += x[i] * y[i], sum2 += x[i], sum3 += y[i], sum4 += x[i] * x[i];
return (sum1 * n - sum2 * sum3) / (sum4 * n - sum2 * sum2);
}
inline double Get_b() {
double sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0;
for (int i = 0; i < n; ++i)
sum1 += x[i] * y[i], sum2 += x[i], sum3 += y[i], sum4 += x[i] * x[i];
return (sum4 * sum3 - sum1 * sum2) / (sum4 * n - sum2 * sum2);
}
int main() {
freopen("data.txt", "r", stdin);
read(n);
for (int i = 1; i <= n; ++i) {
double nx, ny;
scanf("%lf%lf", &nx, &ny);
x.push_back(nx);
y.push_back(ny);
}
double a = Get_a();
double b = Get_b();
printf("y = %lfx + %lf", a, b);
return 0;
}
多维拟合
多维拟合和一维拟合在本质上差别不大,即对多维方程求偏导,解出各个未知量。(因为不会求了,所以水不下去了)