상세 컨텐츠

본문 제목

C언어 최소제곱법을 이용해 직선과 상관계수 구하기

IT/C

by J KIMS 2021. 1. 2. 21:52

본문

반응형

최소제곱법의 개념

 

최소제곱법 또는 최소자승법이란

통계기초에서 배우는 개념인데

제곱들의 합이 최소가 되는 직선을 구하는 방법이다

 

이게 뭔 말이냐면

 

이런 식으로 좌표 위에 점들이 있고 점 사이를 지나는 직선은 무수히 많을 것이다.

그런데 각 점에서 직선위로 내린 직선의 길이(위 이미지에서 y)의 제곱의 합이 최소가 될 때 가장 점들의 경향을 잘 설명해주는 직선 y=ax+b를 구할 수 있다는 이론이다. 

 

그냥 저 네모네모들의 합이 최소가 될 때 가장 정확한 직선을 구할 수 있단 뜻이고,

이걸 파헤치는 글이 아니니 어서 c언어 코드로 넘어가자.

 

 

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;
}
view raw leastSqaure.c hosted with ❤ by GitHub

 

상관계수 구하기

 

이번에는 상관계수를 구하는 코드를 작성해봤다.

위 코드를 살짝 바꾼 건데 leastSqaure함수가 a값을 리턴한다는 점이 좀 다르다.

 

  • 결정계수 = a * a' = r^2
  • 상관계수 = r (결정계수의 제곱근)

 

여기서 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);
}
view raw Rsqaured.c hosted with ❤ by GitHub

 

 

반응형

관련글 더보기

댓글 영역