본문 바로가기

Data Science/EDA

[Data Science / EDA] 야, 너두 EDA 할 수 있어! (1 - 시각화 코드 작성하기 by Python_pyplot)

 부푼 마음으로 인턴 생활을 시작한지 어언 2주가 지났다. 별다른 업무 없이 빈둥대던 첫주가 지나고 나에게 처음으로 주어진 업무가 바로 EDA(Exploratory Data Analysis)다. 남들이 작성해둔 EDA 코드를 보고 따라치는 것이야 아무 문제 없었다. 해당 코드들을 읽고 이해하는 것도 아무 문제 없었다. 문제는 와타시의 무지였다. 자연 그대로의 데이터들을 보고 그들을 파악할 지식과 방법론 따위는 내게 없었다. 그런 나에게 던져진 수십 종류의 테이블들과 그 데이터베이스를 보고 있자니 정신이 멍해지고 손이 달달 떨렸다. 그런 고로 맨바닥부터 화려하게 데이터들을 감싸는 EDA를 해내기까지 나의 A to Z, Step by step 을 기록해 보고자 한다. 훗날의 나와 이 글을 읽을 여러분에게 티끌만큼의 도움이라도 되기를 바란다. 각설하고 본론의 방으로.

 


 

 앞으로 EDA를 하고 있자면 정말 토나오게... 아니, 학을 뗄만큼 많이 해야 될 작업이 바로 시각화이다. 그런 이유로 이번글에서는 Python (필자의 편의상 앞으로의 코드 작성은 Python으로 이루어질 예정) 에 존재하는 라이브러리들을 활용하여 그래프 몇가지를 그려보려고 한다. 최대한 그리는 방법에 대한 것만 다룰 예정이며, 어떤 데이터에 어떤 그래프가 어울리는지와 같은 내용들은 다음으로 미뤄보려고 한다. (O_<) bb


 그 전에 실습환경을 추천드리고 싶다. 아마 EDA 에 Anaconda JupyterNotebook 환경을 많이들 사용하실 텐데, 구글의 Colab이 굉장히 편리하다. (필자는 Colab 환경에서 코드 작성 진행) 별도의 설치가 필요없을 뿐더러 구글 드라이브에 파일을 저장할 수 있고 웹 환경에서 바로 코드 작성이 가능하다는 점이 큰 장점이다. 파일 확장자는 JupyterNotebook 과 동일한 .ipynb 로 사용이 가능하고 Colab으로 작성한 코드는 JupyterNotebook 과 완벽히 호환이 된다. 기존에 JupyterNotebook 을 설치하여 사용 중이던 분들이 아니라면 Colab 으로 실습하는 것을 강력 추천드린다.

  • Colab에서 실습 시작하기는 여기
  • Colab에서 한글 폰트 적용은 여기
  • Colab에서 파일 경로 지정은 여기

 장인은 도구를 신경쓰지 않는다는 말이 있다. 그래서 우리같은 아마추어들은 도구를 굉장히 신경써야 한다. 따라서 시각화를 위한 도구인 라이브러리는 굉장히 중요하다고 할 수 있다. 적재적소에 알맞는 그래프를 그릴 수 있다면 인사이트가 조금 후져도 잘 포장할 수 있을 것이다. Python에서 이루어지는 시각화에는 주로 pyplot, seaborn, folium 과 같은 라이브러리들이 많이 쓰인다. 이외에도 plotnine, plotly, pyecharts, Bokeh 등의 라이브러리가 있다.


matplotlib.pyplot (공식 문서)

 가장 기본적인 Python의 시각화 라이브러리라고 할 수 있겠다. pandasDataFrame 이 기본으로 제공하는 시각화 메소드에서도 바로 이 친구를 사용한다. 데이터를 차트나 플롯(plot)으로 그려줄 수 있는 녀석으로 선 그래프, 막대 그래프, 원형(pie) 그래프, 히스토그램, 박스 그래프, 산포도 등을 표현할 수 있다.

 

 먼저 임포트를 해주어야 함은 당연하다. Colab 환경에서는 별도로 라이브러리 설치가 필요하지 않으니 해당 과정은 생략하겠다. 그리고 중요한 정보는 아니지만 대부분의 사용자들이 plt 로 축약해 사용하고 호칭하기도 하니 우리도 대세에 편승하여 항상 plt 로 사용하는 습관을 들이도록 하자.

import matplotlib.pyplot as plt

 

선 그래프

 그럼 선 그래프부터 간단히 그려보도록 하겠다.

plt.plot([1,2,3,4])

 해당 코드로 하나의 선그래프를 간단히 표현해볼 수 있다. 공식 문서를 보면 파라미터로는 배열형(list, tuple 등)의 자료 혹은 스칼라 자료형을 줄 수 있다고 하니 사용에 참고하시길 바란다. (메소드에 파라미터로 무엇을 줄 수 있는지와 같은 syntax 파악은 개인적으로 공식 문서를 살펴보는 것이 제일 편하다고 생각)

plt.plot([1,2,3,4],[5,6,7,8])

 이렇게 두 개의 그래프도 그릴 수 있다. 하지만 두 개 이상의 그래프를 그리고자 할 때는 아래처럼 각 그래프별로 plot 메소드를 호출하고 show 메소드를 통해 보여주는 것이 낫다.

plt.plot([1,2,3,4])
plt.plot([2,3,4,5])
plt.plot([3,4,5,6])
plt.show()

 이외에도 스타일을 지정해 줄 수 있고 (자세한 스타일 관련 파라미터 설정은 공식 문서이 글에서 잘 설명함)

plt.plot([1,2,3,4], linestyle='--', color='r', marker='*')
plt.xlabel('x_label')
plt.ylabel('y_label')
plt.show()

 범례를 볼 수도 있다.

plt.plot([1,2,3,4])
plt.plot([2,3,4,5])
plt.plot([3,4,5,6])
plt.legend(['a','b'])
plt.show()

 legend 메소드에 매개변수로 범례 목록을 넣어줄 수도 있겠지만 그래프를 정의할 때 label 파라미터를 설정해 준다면 조금 더 현명한 아마추어로 거듭날 수 있다.

plt.plot([1,2,3,4], label='a')
plt.plot([2,3,4,5], label='b')
plt.plot([3,4,5,6], label='c')
plt.legend()
plt.show()

막대 그래프

 막대 그래프는 bar 메소드를 이용하면 된다.

plt.bar([5,2,3,4],[1,2,3,4])
plt.show()

 이런 식으로 그려지는데 앞에 주어지는 파라미터가 인덱스 역할, 뒤에 주어지는 파라미터가 값의 역할이라고 보면 된다.

plt.bar(['a','b','c','d'],[1,2,3,4])
plt.show()

 이렇게 말이다. 물론 이 녀석도 다양한 스타일을 지정해 줄 수 있다. 이 또한 공식문서에서 다양한 파라미터의 종류를 확인하시기 바란다.

plt.bar(['a','b','c','d'],[1,2,3,4], tick_label=['1','2','3','4'], edgecolor='r')
plt.title('Bar Chart')
plt.xlabel('index')
plt.ylabel('value')
plt.show()

여러개의 그래프를 나란히 놓아서 비교해 볼 수도 있다.

data = [1,2,3,4]
plt.bar([i-0.1 for i in range(len(data))],data,width=0.1)
# 위 bar 메소드 속 반복문은 [-0.1, 0.9, 1.9, 2.9] 와 동일하다.
data1 = [2,3,4,5]
plt.bar([i for i in range(len(data))],data1,width=0.1)
# 위 bar 메소드 속 반복문은 [0, 1, 2, 3] 와 동일하다.
data2 = [3,4,5,6]
plt.bar([i+0.1 for i in range(len(data))],data2,width=0.1)
# 위 bar 메소드 속 반복문은 [0.1, 1.1, 2.1, 3.1] 와 동일하다.
plt.legend(['a','b','c'])
plt.show()

 보시면 bar 메소드는 별도의 인덱스명 지정이 없다면 막대를 1.0씩 간격(막대의 중앙 위치)을 두고 그려지는 것을 알 수 있다. 이 점을 이용하여 막대의 두께를 줄이고 막대가 그려지는 위치를 조정하여 서로 다른 세개의 데이터가 묶여있는 것처럼 보이게 그릴 수 있는 것이다.

data1 = [1,1,1,1,1]
data2 = [1,2,1,2,1]
data3 = [2,2,2,2,2]
data4 = [2,1,2,1,2]


plt.bar(range(len(data1)), data1) 
plt.bar(range(len(data2)), data2, bottom=data1)
plt.bar(range(len(data3)), data3, bottom=[a+b for (a,b) in zip(data1, data2)])
plt.bar(range(len(data4)), data4, bottom=[a+b+c for (a,b,c) in zip(data1, data2, data3)])

plt.legend(['data1','data2','data3','data4'])

plt.show()

 흥미로운 방법으로 누적 막대 그래프도 그릴 수 있다. bar 메소드의 bottom 파라미터를 이용하면 해당 막대가 어느 값부터 시작할지 정해줄 수 있는데 이를 이용하여 앞서 그려준 막대의 값을 넣어주면 해당 막대의 윗부분에 이어지게 그릴 수 있는 것이다. 여기에 Pythonzip 메소드를 활용해 다수의 배열을 가지고 계속해서 누적되는 그래프를 그릴 수 있다. 풀어서 설명하자면 data1의 값을 막대로 모두 그린 후, data2의 값을 data1 막대 위쪽에서 시작하게 그렸다. 그 후 data3의 값을 data1data2의 합 윗부분에 그렸으며, 마지막으로 data4의 값을 data1, data2, data3의 합 윗부분에 그려주게 되면 위와 같은 그래프를 얻을 수 있는 것이다. 설명이 장황하지만 잘 이해가 되셨길 바란다.

 

원형 그래프

 다음으로 그려볼 것은 원형(pie) 그래프이다. 

plt.pie([1,2,3])
plt.show()

 이 녀석도 마찬가지로 다양한 스타일 지정이 가능하다. (공식 문서 두둥등장 + 이제야 꺼내는 색상표)

plt.pie([1,2,3], colors=['brown','chocolate','orange'], labels=[1,2,3],
        autopct='%0.3f%%',    # 데이터가 차지하는 비율 보여주기
        # '%0.3f' -> 소수 셋째 자리까지 보여줌 (ex. 33.333)
        # '%0.3f%%' -> 소수 셋째 자리까지 보여주고 뒤에 % 기호 붙여줌 (ex. 33.333%)
        # '%d%%' -> 정수로 반올림해주고 뒤에 % 기호를 붙여줌 (ex. 33%)
        explode=[0,0.1,0.2])
        # 조각을 조금 떨어지게 표현, pie 메소드 호출 시에 넣어준 데이터 순서대로 
        # (b조각이 0.1, c조각이 0.2만큼 떨어진 것)
plt.legend(['a','b','c'])
plt.show()

 조금 달콤해졌다. matplot의 원형 그래프에서 많이 선택하는 옵션은 위에서 선택한 정도다. 좀 더 이쁘고 다양한 옵션을 선택하고 싶다면 다른 라이브러리를 사용하는 것이 바람직하다. 원형 그래프에서 그룹 내 하위 그룹의 비율을 보고싶다면 이중으로 원형 그래프를 중첩하는 괴랄한 방법도 있다. (여기에서 코드 확인 가능)

 

subplot

 여러 개의 그래프를 한 번에 나열하여 볼 수 있게 해주는 메소드다. 백문이불여일타.

#  figure 메소드는 우리가 그림 그릴 캔버스에 대한 설정이라고 생각하면 됨
plt.figure(figsize=(20,4))

# subplot 호출에는 여러 방법이 있지만
# (x축개수, y축개수, 인덱스)
plt.subplot(3,2,1)
plt.pie([1,2,3])

# 한 캔버스에 그리려면 축의 개수는 동일하게 주고 인덱스만 변경
plt.subplot(3,2,2)
plt.bar(['a','b','c','d'],[1,2,3,4])

# 인덱스의 진행은 왼쪽에서 오른쪽으로, 위에서 아래로 진행됨
plt.subplot(3,2,3)
plt.plot([1,2,3,4], linestyle='--', color='r', marker='*')

# 3*2 행렬이므로
# [[1,2],
#  [3,4],
#  [5,6]] 가 인덱스의 형태

plt.subplot(3,2,4)
plt.pie([1,2,3])
plt.subplot(3,2,5)
plt.pie([1,2,3])
plt.subplot(3,2,6)
plt.pie([1,2,3])

plt.tight_layout()    # 위에서 지정한 캔버스 크기에 맞춰 자동으로 그래프들의 크기를 조절해줌
plt.show()

 

 그 밖에도 히스토그램, 산포도(Scatter plot), 박스 그래프 등을 그릴 수도 있지만 시작하는 단계에서는 위 세 종류의 그래프만 완벽히 숙지해도 인사이트를 발굴하기에 충분하다 생각된다. 이 라이브러리는 가장 기본이 되고 심플한 것이 특징이다. 더 알록달록하고 세련된 디자인을 찾는다면 충분히 만족스럽지 않을 수 있다.


 본래 seaborn과 folium, plotly 까지 한번에 다루려 했지만 분량조절의 실패로 다음 글에서 다루도록 하겠다. 마지막으로 훌륭한 도구로 인사이트를 잘 포장한 예시를 다룬 글이 있어 공유한다. 물론 그들은 필자와 달리 인사이트 또한 훌륭했지만 적절한 시각화의 위력을 잘 보여주는 것 같으니 한번 보시면 흥미로우실거라 사료된다. 사료는 '깊이 생각되어 헤아려지다.'라는 뜻으로 사실 일본에서...

 


다음시리즈