우리는 다양한 부면의 데이터를 수집하고 이들 속에 어떤 상관(correlation) 혹은 연관(association) 관계를 찾는다. 이들 데이터 중 일부는 인공의 기준을 세우고 단위를 부여한다. 동일한 속성을 가리키는 값이라 해도 그 단위에 따라 다른 값으로 나타나는데 이로 인해 그 결과가 상이하게 되기도 한다.
예를 들어, 4명의 나이와 키를 아래와 같이 수집했고, 이를 아래 표와 같이 정리했다고 하자.
Table 1. Age(in years) and height(in centimeters) of 4 people.
Person
|
Age (years)
|
Height (cm)
|
A
|
25
|
180
|
B
|
30
|
180
|
C
|
25
|
165
|
D
|
30
|
165
|
Python으로 이들 데이터를 matplotlib 모듈을 이용해 도표를 그려보자.
참고로 matplotlib는 Python 2.x 만 제공하고 있고 또 LaTeX를 기능을 사용하는 경우도 있기 때문에 공식 웹 사이트가 아닌 다른 곳에서 Python 3.2용 matplotlib를 받아서 설치 해야 한다.
이 사이트는 Unofficial Windows Binaries for Python Extension Packages로 그 외에도 유용한 패키지가 많다. 그리고 Windows용 TeX는 TeX Live를 받아서 설치 했는데 Linux Mint에서와 마찬가지로 texlive-latex-base와 texlive-latex-recommended 뿐만 아니라 texlive-math-extra와 texlive-fonts-extra도 함께 설치 해야 한다. 또 Windows에서 TeX Live 패스 설정을 하지 않는다면 문제가 발생하는데, 이는 googling으로 해결하면 된다. 물론 TeX 설치가 힘들다면 그냥 matplotlib 모듈에서 TeX 기능을 사용치 않거나 굳이 써야 하면 Mac이나 Linux에서 사용하는걸 권한다. (개인적으론 Mac에서 설정 잡는 것이 편했다.)
1: import matplotlib.pyplot as plt
2:3: fig = plt.figure()4:5: fig.suptitle('The dependence on the choice of measurement units', fontsize=14, fontweight='bold')6: ax = fig.add_subplot(111)7: fig.subplots_adjust(top=0.85)8:9: ax.set_title('Height versus age')10: ax.set_xlabel('Age (YEARS)')11: ax.set_ylabel('Height (CM)')12:13: x = [25, 30, 25, 30] # age14: y = [180, 180, 165, 165] # height15: persons = ["A", "B", "C", "D"]16:17: ax.scatter(x,y,s=120, zorder=2)18:19: for i in range(4):20: #ax.plot(x[i], y[i], c="red", marker = 'o')
21: #ax.scatter(x[i], y[i],s=70, zorder=2)22: ax.text(x[i], y[i] * 1.01 , persons[i], color='black')23:24: ax.axis([15, 50, 150, 190])25: ax.grid()26: plt.show()27:
위 코드를 실행하면 다음과 같은 도표를 확인 할 수 있다. 이 도표를 통해 데이터를 눈으로 가까운 것과 먼 것을 나눠보면 {A, B}와 {C, D}가 될 것이다.

Table 1에서 신장 값을 센티미터 단위로 나타냈던 것을 피트 단위를 이용한다면 아래 Table 2와 같이 나타난다. (1ft = 30.48 cm)
Table 2. Age(in years) and height(in feet) of 4 people.
Person
|
Age (years)
|
Height (feet)
|
A
|
25
|
5.91
|
B
|
30
|
5.91
|
C
|
25
|
5.41
|
D
|
30
|
5.41
|
이 데이터를 도표 상 나타내도록 코드를 일부 수정하여 아래 코드에 나타내었다. 단, 수정된 위치 및 추가 된 것만 나타냈다. 위 코드 행과 맞춰보면 된다.
...11: ax.set_ylabel('Height (Ft)')...16: y = [float(("%1.2f") % (i / 30.48)) for i in y]
...24: ax.axis([15, 50, 3, 8])

이 도표를 통해 데이터를 눈으로 가까운 것과 먼 것을 나눠보면 {A, C}와 {B, D}가 될 것이다. 물론 이 두 도표는 Height 축의 비율(scale)에 의한 착시 현상이 존재한다. 아래 코드와 같이 24 행을 수정하면 figure01과 같이 나타낼 수 있다. 결국 이 비율 문제도 이 포스트에서 다루는 문제와 같은 것이다.
24: ax.axis([15, 50,float(("%1.2f") % (150 / 30.48)),
float(("%1.2f") % (190 / 30.48))])
이런 문제를 해결하기 위해서는 데이터를 단위가 없는 표준화된 데이터로 변환하는데 일반적으로 표준편차(standard deviation)를 구해 표준점수(standard score, z-score)로 환산한다. 다만 표준편차의 경우 데이터 값과 그 표본 평균(일반적으로 산술평균)차를 제곱함으로 인해 점수가 부풀려지는 경우가 발생할 수 있다.
절대 평균 편차(mean absolute deviation)을 구하면 이런 경향을 피할 수 있다. 절대 평균 편차는 각 값과 표본 평균 차의 절대치를 취해 원래 값과 비례하도록 한다.

이를 구하여 도표로 그리는 코드를 다음과 같이 작성했고 그 결과는 아래와 같다. 이 코드를 실행 후, 다시 17행에 있는 피트 단위로 변환하는 코드의 주석을 제거 후 실행해도 동일한 결과를 얻게 된다. 14~16행에 데이터를 좀 더 추가해서 수행해보는 것도 좋다.
1: import matplotlib.pyplot as plt
2: import math
3:4: fig = plt.figure()5:6: fig.suptitle('The dependence on the choice of measurement units', fontsize=14, fontweight='bold')7: ax = fig.add_subplot(111)8: fig.subplots_adjust(top=0.85)9:10: ax.set_title('Height versus age')11: ax.set_xlabel('Age (z-score)')12: ax.set_ylabel('Height (z-score)')13:14: x = [25, 30, 25, 30] # age15: y = [180, 180, 165, 165] # height16: persons = ["A", "B", "C", "D"]17: #y = [float(("%1.2f") % (i / 30.48)) for i in y]
18:19: # calculates means of x and y20: mx, my = math.fsum(x) / len(x), math.fsum(y) / len(y)21:22: # calculates mads of x and y23: sx, sy = (1/len(x)) * math.fsum(math.fabs(i - mx) for i in x), \24: (1/len(y)) * math.fsum(math.fabs(i - my) for i in y)25:26: # calculates each z-scores of x and y elements27: # and assigns them into new lists madx, mady
28: # z_socre = (xi - mean) / s_mad29: madx, mady = [ (i - mx) / sx for i in x ], \30: [ (i - my) / sy for i in y ]31:32: ax.scatter(madx, mady, s=120, zorder=2)33:34: for i in range(4):35: ax.text(madx[i], mady[i] * 1.2 , persons[i], color='black')36:37: ax.axis([-2, 2, -2, 2])38: ax.grid()39: plt.show()

이 포스트에서는 동일한 속성에 대한 여러 단위에 의한 표현형을 가지는 값을 단위를 배제하고 표준 점수로 나타내는 과정을 Python 3.2와 matplotlib 모듈로 작성해 보였다. 여기에 보인 도표는 모두 matplotlib에서 그려진 이미지를 저장한 것이다. 실제 코드를 실행하면 아래 그림과 같은 윈도우가 실행된다. 저장 버튼을 눌러 PNG 포맷 이미지로 저장 매체에 저장할 수 있다.
이 포스트를 통해 원래 전하고자 했던 바는, 컴퓨터 프로그래밍 언어에 있어 마일스톤(milestone)인 Python의 간편함과 유용성을 보이고자 한데 있다. 물론 matplotlib 모듈의 경우 Windows 환경에서 Python 3.2와 조합 시 설치부터 어려움을 유발하고 또한 matplotlib 자체가 차트 및 그래프의 A to Z까지 모두 제공하다 보니 일견 어려울 수도 있지만 matplotlib 웹 사이트 내 갤러리 및 예제를 참조하다 보면 Python 문법 차체의 간결함과 일관된 패턴이 상승효과를 유발해 수월하게 익힐 수 있다. 이제 공과 대학은 Matlab과 작별을 고해도 될 시점이라 생각한다.
댓글 없음:
댓글 쓰기