다음과 같은 자료가 있다고 가정하자.

애기장대 10 개체의 줄기와 뿌리 길이를 나타낸 표 (가상데이터)

개체 번호 줄기 길이 (cm) 뿌리 길이 (cm)
1 8 5
2 7 4
3 5 3
4 6 7
5 6 8
6 4 2
7 6 6
8 5 4
9 5 2
10 9 6
11 5 4
12 6 4
14 7 8
13 10 12
15 7 9

이 표는 가상데이터이므로 실제 과학적 사실과는 아무런 상관이 없다는 것을 미리 알린다.

애기장대의 줄기와 뿌리의 길이가 서로 얼마나 연관성이 있는지를 판단하는 방법이 있을까? 이번 글에서는 또 다른 그래프인 산점도(scatter plot)와, 회귀 직선(regression analysis)을 구하는 방법을 설명하고, 프로그래밍 언어를 이용해 회귀직선 그래프를 그려보도록 하겠다.


산점도 그리기

시간의 변화에 따른 애기장대의 줄기 길이를 재는 것과 같은 변수가 하나(줄기 길이)인 자료와 달리, 지금과 같이 변수가 두 개(줄기 길이, 뿌리 길이)인 자료로부터 그래프를 그릴 때, 우리는 산점도(scatter plot)를 그려볼 수 있다. 줄기 길이를 x축, 뿌리 길이를 y축으로 하여 산점도를 그려보자. python을 이용해서 그려보았다.

import matplotlib.pyplot as plt
import numpy as np

x = [8, 7, 5, 6, 6, 4, 6, 5, 5, 9, 5, 6, 7, 10, 7]  # 줄기 길이
y = [5, 4, 3, 7, 8, 2, 6, 4, 2, 6, 4, 4, 8, 12, 9]  # 뿌리 길이
area = 100 # 점의 면적

plt.scatter(x, y, s=area, alpha=0.5) # x, y를 좌표값으로 산점도를 그림, alpha는 점의 투명도
plt.axis([4, 11, 0, 12]) # 각 축의 범위를 표시 ([xmin, xmax, ymin, ymax])
plt.show()

scatter1

x축 : 줄기 길이        y축 : 뿌리 길이

언뜻 봐서는 줄기 길이가 길어질 수록 뿌리 길이도 길어지는 것처럼 보인다. 이러한 두 변수의 관계를 일반화된 선형관계의 평균으로 돌아가게 하는 것을 회귀(Regression)이라 한다.


회귀직선 구하기

위의 산점도로부터 직선의 그래프를 구하려면, 직선의 방정식을 알아야 할 것이다. 직선의 방정식은 다음과 같다.

y = mx + b (m, b는 상수)

따라서 m과 b의 값을 알면 직선을 그릴 수 있다. x 좌표값과 y 좌표값의 평균을 알면 이를 구할 수 있다. 다음 공식을 보자.

m

b

위 공식의 유도 공식은 칸 아카데미를 참고하자. 직관력을 기르는데 도움이 되는 사이트이다.

bar{x} = 모든 x 값의 평균 = 6.4
bar(x ^2) = 모든 x 제곱값의 평균 = 43.46 bar{y} = 모든 y 값의 평균 = 5.6 bar{xy} = 각 x와, y값을 곱한 값들의 평균 = {(8x5) + (7x4) + … + (7 x 9)} / 15 = 38.93

m = -3.09 / -2.5 = 1.24 b = 5.6 - 7.2 = -2.34 따라서 직선의 방정식은 y = 1.24x - 2.34

따라서 직선 그래프를 다음과 같이 그릴 수 있다.

import matplotlib.pyplot as plt

x = pd.Series([8, 7, 5, 6, 6, 4, 6, 5, 5, 9, 5, 6, 7, 10, 7])  # 줄기 길이
y = pd.Series([6, 4, 3, 7, 8, 2, 6, 4, 2, 6, 4, 4, 8, 12, 9])  # 뿌리 길이
plt.axis([4, 11, 0, 12]) # 각 축의 범위를 표시 ([xmin, xmax, ymin, ymax])
plt.plot(x, y, 'o') # 'o'는 데이터를 점으로 표시하라는 의미
x = [a for a in range(13)]
y = [(1.24 * b) - 2.34 for b in range(13)] # 방정식 y = 1.24x - 2.34
plt.plot(x,y)

scatter2

사실 이렇게 다소 복잡한 계산을 거치지 않아도, 라이브러리 함수를 이용하면 쉽게 그릴 수 있다. 다만 회귀 직선이 어떻게 유도되는 것인지 설명하기 위해 원래 계산방식을 작성했다. 계산 설명을 통해 회귀직선 그래프를 그릴 때도 분산과 산술평균이 중요한 역할을 한다는 것을 보여주었다. 다음은 기계학습 라이브러리를 이용해서 회귀직선을 그린 것이다.

import matplotlib.pyplot as plt # 그래프 그리기용 라이브러리
import numpy as np # 산술 라이브러리
from sklearn.linear_model import LinearRegression # 기계학습 - 회귀 라이브러리
import pandas as pd # 데이터를 편리하게 다루기 위한 라이브러리

x = pd.Series([8, 7, 5, 6, 6, 4, 6, 5, 5, 9, 5, 6, 7, 10, 7])  # 데이터를 시리즈 형으로 저장
y = pd.Series([6, 4, 3, 7, 8, 2, 6, 4, 2, 6, 4, 4, 8, 12, 9])  
plt.plot(x, y, 'o')
plt.axis([4, 11, 0, 12])
line_fitter = LinearRegression() # 회귀모델 적용
line_fitter.fit(x.values.reshape(-1, 1), y) # x가 2차원 모델이므로 reshape(-1,1)적용시킴
plt.plot(x,line_fitter.predict(x.values.reshape(-1,1))) # 회귀직선 예측하여 작성
plt.show()

135

그렇다면 이렇게 추정한 선형 모형이 주어진 자료에 얼마나 적합한지 측정해보도록 하자.

결정계수 (coefficient of determination)

편차

결정계수는 변수에 대한 모형의 설명력을 나타내는 척도로 사용된다. 후에 다루겠지만, 분산분석 표를 해석할 때에는 모형의 유의성 뿐만 아니라 설명력(R^2)도 함께 확인해야 한다. 모형이 유의하다고 해서 꼭 데이터 해석에 유용하지는 않을 수 있다.

엑셀을 이용해서 수동으로 결정계수를 구해보자. 이렇게 구해보면 결정계수가 무엇인지 이해할 수 있을 것이다. 먼저 다음과 같이 엑셀에 값을 입력한다. raw data의 좌표값을 입력하면 된다.

sdf

이 후 다음 열에 y의 예측값(y^)을 기록한다. 직선의 방정식(여기서는 y = 1.24x - 2.34)에 x값을 넣었을 때 나오는 y값을 입력하면 된다. 즉 y는 실제 데이터값, y^는 예측값이다.

sfe

이후 y에서 (실제값에서 예측값을 빼준값)^2을 구한다. 이 값들을 모두 더해주면 52.342의 값이 나온다. 직선의 예측값과 실제 데이터 값의 오차를 구한 것이므로, 0.06은 회귀직선으로 설명되지 않는 오차값들의 총합이다.

sddf

이번엔 실제값에서 실제값의 평균을 뺀 뒤, 제곱한 값을 구해보자. 참고로 여기서 표본의 전체 개수로 나누어 주기만 하면 분산값이 나온다.

(y - bar(y))^2

12345

실제값과 평균을 비교한 것이니, 여기서 109.6의 값은 오차의 총합 이라 할 수 있다. 따라서 회귀직선으로 설명되지 않는 오차값들의 총합 에서 오차의 총합을 나누어주면 회귀직선으로 설명되지 않는 오차값의 백분율을 구할 수 있고, 1에서 이 백분율을 빼주면 결과적으로 자신이 그린 회귀직선이 기존의 변수들과 관련하여 얼마만큼의 설명력을 가지는지 추정할 수 있다. 이를 결정계수라 한다.

1 - (52.342/109.6) = 0.523 = 결정계수 (r^2)

엑셀을 이용한 회귀직선 구하기

최종적으로 엑셀을 이용해서 간편하게 회귀직선을 구하는 방법을 알아보겠다.

  1. 데이터를 입력한다.

sdf

  1. 데이터 영역을 드래그 한 뒤, 산점도 그래프를 만든다.

    삽입 클릭 > 분산형 클릭 > 표식만 있는 분산형 클릭

  2. 해당 점을 마우스 오른쪽 클릭한 뒤, 추세선 추가를 누른다. 이후 추세선 옵션에서 수식을 차트에 표시, R-제곱값을 차트에 표시하기를 누른다. 다음과 같은 그래프가 완성된다.

wjawja