最小二乘法学习笔记

一维数据拟合

参考自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;
}

多维拟合

多维拟合和一维拟合在本质上差别不大,即对多维方程求偏导,解出各个未知量。(因为不会求了,所以水不下去了)

posted @ 2021-09-27 20:21  ZmeetL  阅读(151)  评论(0编辑  收藏  举报