정보과학융합탐구

3. MSE, MAE를 C로 구현해보자!!

Quettabyte 2023. 3. 13. 18:05

벌써 3번째 게시글을 쓰게 되었네요. 이번 게시글은 첫번째 정보과학융합탐구 게시글인데요. 평소에 관심을 가지던 주제를 코딩으로 구현해보는 과제가 주어졌습니다.  어떤 주제를 정해야할지 고민을 많이 했지만 결국 제가 주제는 MSE, MAE 인데요.

 

-MSE, MAE란 무엇일까?

머신러닝 회귀 모델을 평가할때 사용되는 지표의 종류입니다.

 

우선 MSE는 mean squared error의 약자로 평균제곱오차를 가리키는데요. 평균제곱오차는 말 그대로 오차를 제곱한 값에  평균을 취한 값입니다. 

<출처:https://velog.io/@tyhlife/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%ED%9A%8C%EA%B7%80-%EB%AA%A8%EB%8D%B8%EC%9D%98-%ED%8F%89%EA%B0%80-%EC%A7%80%ED%91%9C>

 

머신러닝에서 가장 많이 쓰이는 손실 함수 중 하나로 값이 0에 가까울수록 예측 값이 실제값에 가깝다는것이기 때문에 정확도가 높다고 할 수 있습니다. 지표가 직관적으로 나타나 분석에 용이하지만 제곱한다는 특성때문에 1미만의 에러는 훨씬 작아지고 1 이상의 에러는 훨씬 커진다는 단점이 있습니다. 또한, 예측값이 실제값보다 작은지 큰지도 알 수 없습니다. 그리고 특이값이 있다면 그 값에 큰 영향을 받습니다. 스케일에 의존적이라는 단점도 있겠네요.

 

이러한 MSE와 비슷하지만 다른 지표로 MAE가 있는데요. MAE는 mean absolute error의 약자로 평균절대오차를 가리킵니다. 평균절대오차는 오차에 절댓값을 취하여 평균을 취한 값입니다. 

<출처:https://velog.io/@tyhlife/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%ED%9A%8C%EA%B7%80-%EB%AA%A8%EB%8D%B8%EC%9D%98-%ED%8F%89%EA%B0%80-%EC%A7%80%ED%91%9C>

MAE도 마찬가지로 값이 0에 가까울수록 정확도가 높다고 할 수 있겠죠. MAE는 지표가 직관적이기도 하지만 예측값과 실제값의 단위가 같기때문에 분석하기에 용이합니다. 특잇값의 영향도 MSE보다는 적을것입니다. 그러나 오차에 절댓값을 취하기 때문에 예측값이 실제보다 작은지 큰지를 알 수 없고, 스케일에 의존적이라는 단점을 가지고 있습니다. 

 

-이것들은 어디에 쓰이는 걸까?

 

위에서 언급한대로 모델 성능 평가에 쓰이는데요. 모델 성능 평가는 말그대로 예측값이 실제값과 얼마나 차이가 나는지에 대한 평가인데요. 이를 통해 과적합 현상을 방지하고 최적의 모델을 찾을 수 있게 됩니다. 모델에 따라 다양한 평가 지표가 존재하는데(아래 그림 참고) 저는 이주 회귀 모델 평가에 사용되는 2가지 지표에 대해 다루었습니다. 다른 방법들도 앞으로 기회가 된다면 블로그에 업로드 하도록 하겠습니다!

 

-C코드로 구현해보자

파이썬으로는 구현해보기도 했고 라이브러리를 이용하면 어렵지 않게 이용할 수 있지만 이번 기회에 C로 구현해보기로 하였습니다. 알고리즘은 다음과 같이 설계하였습니다.

ax+b라는 함수를 이용하여 예측하도록 하였고 배열에 n개의 x값과 실제 값을 입력받도록 하였습니다. 그다음 x값을 토대로한 예측값과 입력받은 실제값 사이의 차이를 분석해보는 알고리즘을 설계하였습니다. 

#include <stdio.h>
#include <stdlib.h>  //abs함수 사용을 위한 라이브러리 

int main(){
	int arr[100][2];    //x값과 실제값 저장 
	int n,a,b;  //n개의 데이터, a는 기울기, b는 y절편 
	double sumse=0;  //제곱오차들의 합
	double sumae=0;	//절대오차들의 합 
	printf("데이터의 개수:");    //변수 입력 
	scanf("%d",&n); 
	printf("기울기:");
	scanf("%d",&a);
	printf("y절편:");
	scanf("%d",&b);
	for(int i=1;i<=n;i++){    //데이터의 갯수만큼 입력 받기 
		printf("%d번째 데이터 입력(x값,실제값):",i);   //데이터 입력 
		scanf("%d,%d",&arr[i][1],&arr[i][2]);     //배열의 1열은 x값, 2열은 실제값 
		
		sumse+=(arr[i][2]-(a*arr[i][1]+b))*(arr[i][2]-(a*arr[i][1]+b));   //제곱 오차 계산 
		sumae+=abs((arr[i][2]-(a*arr[i][1]+b)));   //절대 오차 계산(abs함수 이용) 
	}
	for(int i=1;i<=n;i++){
	printf("x값:%d   실제 값:%d    예측값 :%d\n",arr[i][1],arr[i][2],a*arr[i][1]+b);  //데이터 나열 
}
	printf("MSE값:%.1f\n",sumse/n);    //결과값 소숫점 첫째자리까지 출력 
	printf("MAE값:%.1f",sumae/n);
}

위의 내용을 구현한 코드입니다. 

 

<실행 결과>

실행 결과 잘 작동하였습니다. 5개의 데이터를 가지고 실험을 해보았는데 직접 계산을 해보았을때 

 

MSE: {(9-8)^2 + (13-6)^2 + (11-29)^2 + (25-30)^2 + (17-20)^2}/5=81.6

MAE: {|9-8| + |13-6| + |11-29| + |25-30| + |17-20|}/5 =6.8

 

이므로 계산이 잘 이루어지는것을 볼 수 있습니다. 복잡한 코드는 아니였어서 오류 없이 쉽게 구현할 수 있었던것 같아요.성공해서 매우 뿌듯하네요!

 

첫 정.융.탐 게시물인 만큼 아직 게시물에서 부족함이 많이 느껴지지만 오늘도 글을 읽어 주신 분들께 모두 감사하다는 말을 전하고 싶습니다. 앞으로 더욱 유용한 블로그가 되기 위하여 노력하겠습니다. 그럼 빠이!