- •4.1. Метод наименьших квадратов
- •4.2. Простая линейная регрессия
- •4.3. Простая нелинейная регрессия
- •4.4. Регрессия, нелинейная относительно параметров
- •4.5. Примеры решения задач
- •5. Временные ряды
- •5.1. Определения
- •5.2. Постановка задач сглаживания и прогноза
- •5.3. Решение задач сглаживания и прогноза методом наименьших квадратов
- •Пример выполнения задания 1
- •Программа
- •Результаты работы программы
- •Пример выполнения задания 2
- •Пример выполнения задания 1
- •Результаты работы программы
- •Пример выполнения задания 2
- •Результаты работы программы
- •Обработка экспериментальных данных на эвм Учебное пособие
- •Редакционно-издательский отдел гоувпо «Комсомольский-
- •681013, Комсомольск-на-Амуре, пр. Ленина, 27.
- •681013, Комсомольск-на-Амуре, пр. Ленина, 27.
Пример выполнения задания 1
Задание.
Построить
алгоритм для аппроксимации функции
на отрезке
регрессионной функцией
с использованием метода наименьших
квадратов. Разработать программу,
реализующую этот алгоритм. Размерность
равномерной сетки равна 21.
Решение. Построение алгоритма в данном случае заключается в построении системы линейных уравнений и обоснования существования и единственности решения этой системы линейных уравнений. В дальнейшем будем опираться на материал, изложенный в п.п. 4.3.
Сначала построим сетку
и таблицу данных. Так как сетка равномерная
и число узлов сетки равно 21, то число
отрезков
равно 20 (
).
Обозначим через
шаг, который вычисляется по формуле
.
В нашем случае
,
.
Введем сетку на отрезке
:
.
Узлы сетки находятся по формуле
,
.
Значение
находится
по формуле
,
.
Таким образом, по формуле функции
на отрезке
построена таблица данных размерности
21 с равномерным шагом. Отметим, что в
нашем случае эта таблица является
интерполяционной таблицей, так как
данные не содержат погрешностей.
Функцию
мы будем аппроксимировать функцией
методом наименьших квадратов.
Следовательно, будем искать такие
значения параметров
,
и
,
при которых функция
достигает
минимума, т.е.:
.
Используя необходимые
условия экстремума функции нескольких
переменных, получаем нормальную
систему для определения параметров
,
и
:
,
,
.
Так как функция g
является линейной функцией относительно
,
и
,
то получаем систему линейных уравнений.
Запишем первое уравнение:

Умножив обе части уравнения на –0.5 и преобразовав, получим:
.
Запишем это уравнение в виде:
.
Второе уравнение:

Умножив обе части уравнения на –0.5 и преобразовав, получим:
.
Запишем это уравнение в виде:
.
Третье уравнение получаем аналогично:
.
Запишем систему линейных уравнений:

Мы получили систему
линейных уравнений с симметричной
матрицей. Эта матрица невырожденна, так
как функции
линейно независимы. Следовательно,
система линейных уравнений относительно
неизвестных a, b
и c имеет единственное
решение, которое находится методом
Гаусса с частичным выбором ведущего
элемента.
Зная параметры
,
и
,
мы можем найти значение функции
в
любой точке отрезка
.
Значение среднеквадратичной погрешности
находится по формуле
.
На печать выводится значение
среднеквадратичной погрешности и
таблица значений функций
и
в узлах сетки, т.е. значения
,
,
,
.
Отметим, что среднеквадратичная погрешность R может принимать достаточно большие значения. Связано это с тем, что эта погрешность является абсолютной погрешностью, а не относительной, а также с тем, что регрессионная функция может быть выбрана неудачно.
Программа
#include <stdio.h>
#include <math.h>
#include <conio.h>
// Функция f(x)
float fn (float x)
{ return (pow(2,x)-3*x+4); }
// Функция g(A ,B ,C, x)
float gx (float A,float B,float C,float x)
{ return (A*sin(x)+B*x+C); }
// Функция GaussMethod - решает СЛУ размерности 3
// Входные параметры: А - матрица, В - вектор, Х - вектор неизвестных
void GaussMethod(float A[3][3],float B[3],float X[3])
{
int i,j; //счетчики циклов
// Решение системы уравнений
// k-счетчик циклов
// numb-номер строки с ведущим элементом
// max-максимальный по модулю элемент не преобразованного столбца
// str,bstr- используются при перестановке строк
// L-коэффициент преобразования
int numb=0, k;
float max, str, bstr, L;
// Прямой ход метода Гаусса
for (j=0;j<2;j++)
{
max = fabs(A[j][j]);
numb = j;
// определение максимального элемента в столбце
for (i=j;i<3;i++)
{
if (max<fabs(A[i][j]))
{ max=fabs(A[i][j]); numb=i; };
};
// если максимум - не диагональный элемент, то...
if (numb!=j)
{
// ...замена строк
for (i=0;i<3;i++)
{
str = A[numb][i];
A[numb][i] = A[j][i];
A[j][i] = str;
};
bstr = B[numb];
B[numb] = B[j];
B[j] = bstr;
};
// преобразование столбца
for (i=j+1;i<3;i++)
{
L = -(A[i][j]/A[j][j]); // вычисление коэффициента
A[i][j] = 0.0;
// обнуление элемента текущего столбца
for (k = j+1;k<3;k++) { A[i][k]=A[i][k]+A[j][k]*L; };
// и вычисление последующих в строке
B[i] = B[i]+B[j]*L;
};
};
// Обратная подстановка
for (j=2;j>=0;j--)
{
X[j] = B[j]/A[j][j];
if (j!=2)
{
for (i=2;i>j;i--) {X[j] = X[j]-A[j][i]*X[i]/A[j][j];};
};
};
}
// Главная функция
void main()
{
clrscr();
float Xi[21],Yi[21], // таблица данных
a[3][3],b[3],x[3]; // а - матрица, b - вектор,
// x - вектор неизвестных
float A=0,B=0,C=0; // искомые параметры функции g(A, B, C, x)
float h=0; // шаг
int n=20; // число отрезков - n
float ai=-2,bi=3; // отрезок [-2;3]
float R=0; // значение среднеквадратичной погрешности
h = float(bi-ai)/n; // вычисляем шаг
// Создание таблицы данных
for(int i=0;i<=n;i++)
{
Xi[i] = ai+i*h;
Yi[i] = fn(Xi[i]);
}
// Обнуление элементов матрицы а и вектора b
for(i=0;i<3;i++)
{
b[i] = 0;
for(int j=0;j<3;j++) { a[i][j] = 0;}
}
// Заполнение матрицы а и вектора b
for(i=0;i<=n;i++)
{
a[0][0] = a[0][0] + sin(Xi[i]) * sin(Xi[i]);
a[0][1] = a[0][1] + Xi[i] * sin(Xi[i]);
a[0][2] = a[0][2] + sin(Xi[i]);
a[1][1] = a[1][1] + Xi[i] * Xi[i];
a[1][2] = a[1][2] + Xi[i];
b[0] = b[0] + Yi[i] * sin(Xi[i]);
b[1] = b[1] + Xi[i] * Yi[i];
b[2] = b[2] + Yi[i];
}
a[2][2] = n+1;
a[1][0]=a[0][1];
a[2][0]=a[0][2];
a[2][1]=a[1][2];
// Нахождение неизвестных х[3] методом Гаусса с частичным выбором
//ведущего элемента
GaussMethod(a,b,x);
A = x[0]; B = x[1]; C =x [2]; // искомые параметры A, B, C
// регрессионной функции g
// Расчет значений функции g
float Gi[21];
for(i=0;i<=n;i++)
{
Gi[i] = gx(A,B,C,Xi[i]);
}
// Вычисление среднеквадратичной погрешности
for(i=0;i<=n;i++)
R=R+(Yi[i]-gx(A,B,C,Xi[i]))*(Yi[i]-gx(A,B,C,Xi[i]));
R=sqrt(R/(n+1));
// Вывод значений
printf("Узлы сетки\tФункция f Регрессионная функция g\n");
for(i=0;i<=n;i++)
printf(" %.2f \t %.2f \t\t %.2f \n",Xi[i],Yi[i],Gi[i]);
printf("\n\nЗначение среднеквадратичной погрешности равно : %.2g",R);
getch();
}
