최소제곱법 또는 최소자승법이란
통계기초에서 배우는 개념인데
제곱들의 합이 최소가 되는 직선을 구하는 방법이다
이게 뭔 말이냐면
이런 식으로 좌표 위에 점들이 있고 점 사이를 지나는 직선은 무수히 많을 것이다.
그런데 각 점에서 직선위로 내린 직선의 길이(위 이미지에서 y)의 제곱의 합이 최소가 될 때 가장 점들의 경향을 잘 설명해주는 직선 y=ax+b를 구할 수 있다는 이론이다.
그냥 저 네모네모들의 합이 최소가 될 때 가장 정확한 직선을 구할 수 있단 뜻이고,
이걸 파헤치는 글이 아니니 어서 c언어 코드로 넘어가자.
위 식을 바탕으로 코드를 작성해보자
배열의 값들은 확인을 위해 인터넷에 돌아다니는 예제를 갖다 씀 (출처를 남기고 싶은데 링크를 잃어버림..)
- math.h를 사용하고 있음. 컴파일 할 때 -lm 옵션 필요
- leastSqaure는 최소제곱법을 이용해 a와 b를 구하는 함수. 인자로 (배열1, 배열2, 데이터 수)를 받음
- mean은 주어진 값의 평균을 구하는 함수 (x바와 y바를 구할 때 필요). 인자로 (배열1, 데이터 수)를 받음
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
void leastSquare(int arr1[], int arr2[], int n); | |
float mean(int arr[], int n); | |
int main(void) { | |
int arr1[4] = { 10,20,30,40 }; | |
int arr2[4] = { 71,45,24,8 }; | |
leastSquare(arr1, arr2, 4); | |
} | |
void leastSquare(int arr1[], int arr2[], int n) { | |
// Calculate mean of arr1, arr2 | |
float x_bar = mean(arr1, n); | |
float y_bar = mean(arr2, n); | |
// y = ax + b | |
float a, b; | |
float sum1 = 0, sum2 = 0; | |
// Calculate sum1 , sum2 | |
for (int i = 0; i < n; i++) { | |
sum1 += (arr1[i] - x_bar) * (arr2[i] - y_bar); | |
sum2 += pow((arr1[i] - x_bar), 2); | |
} | |
//printf("sum1 : %lf, sum2 : %lf\n", sum1, sum2); | |
// Calculate a | |
a = sum1 / sum2; | |
// Calculate b | |
b = y_bar - a * x_bar; | |
printf("y = %lfx + %lf\n", a, b); | |
} | |
float mean(int arr[], int n) { | |
float sum = 0, mean = 0; | |
// sum of arr | |
for (int i = 0; i < n; i++) { | |
sum += arr[i]; | |
} | |
mean = sum / n; | |
//printf("sum : %lf, mean : %lf\n", sum, mean); | |
return mean; | |
} |
이번에는 상관계수를 구하는 코드를 작성해봤다.
위 코드를 살짝 바꾼 건데 leastSqaure함수가 a값을 리턴한다는 점이 좀 다르다.
여기서 a'는 x축과 y축을 바꿔서 계산한 a값이다.
leastSqaure에서 받아온 a값들을 calculateR에 넣어서 상관계수를 구한다.
상관계수가 1에 가까울 수록 상관이 높다고 하고 보통 0.5이하면 상관이 낮다고 보는 것 같다.
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
float leastSquare(int arr1[], int arr2[], int n); | |
float mean(int arr[], int n); | |
void calculateR(float a1, float a2); | |
int main(void) { | |
int arr1[4] = { 10,20,30,40 }; | |
int arr2[4] = { 71,45,24,8 }; | |
a12 = leastSquare(arr1, arr2, 4); | |
a21 = leastSqaure(arr2, arr1, 4); | |
calculateR(a12, a21); | |
} | |
float leastSquare(int arr1[], int arr2[], int n) { | |
// Calculate mean of arr1, arr2 | |
float x_bar = mean(arr1, n); | |
float y_bar = mean(arr2, n); | |
// y = ax + b | |
float a, b; | |
float sum1 = 0, sum2 = 0; | |
// Calculate sum1 , sum2 | |
for (int i = 0; i < n; i++) { | |
sum1 += (arr1[i] - x_bar) * (arr2[i] - y_bar); | |
sum2 += pow((arr1[i] - x_bar), 2); | |
} | |
//printf("sum1 : %lf, sum2 : %lf\n", sum1, sum2); | |
// Calculate a | |
a = sum1 / sum2; | |
// Calculate b | |
b = y_bar - a * x_bar; | |
printf("y = %lfx + %lf\n", a, b); | |
return a; | |
} | |
float mean(int arr[], int n) { | |
float sum = 0, mean = 0; | |
// sum of arr | |
for (int i = 0; i < n; i++) { | |
sum += arr[i]; | |
} | |
mean = sum / n; | |
return mean; | |
} | |
void calculateR(float a1, float a2) { | |
float rr = a1 * a2; | |
float r = sqrt(rr); | |
printf("coefficient of determination : %lf\n", rr); | |
printf("correlation coefficient : %lf\n", r); | |
} |
C언어 텍스트, 바이너리 파일 읽기 쓰기 (2) | 2020.12.02 |
---|---|
C언어 수치계산 - 다항식 계산 알고리즘 (호너법 Horner's method) (2) | 2020.11.23 |
C언어 수치계산 미분방정식 오일러법, 4차 룽게 쿠타법 알고리즘 (0) | 2020.09.05 |
C언어 수치계산 수치적분 (구분구적법, 사다리꼴, 심슨 공식) (0) | 2020.09.03 |
C언어 예제 두 수의 합 구하기 (0) | 2020.06.04 |
댓글 영역