목차
데이터 분석 의뢰를 받으면 의례적으로 데이터 경향성 확인한다는 말을 하곤 한다. 데이터 경향성이란 데이터가 갖는 특성을 의미하는 것으로 가시화(visualization)를 통해 확인할 수 있다. 일반적으로 엑셀에서 데이터 그래프를 그려보곤 하는데, 이와 같은 행위들이 경향성을 확인하는 것이다. 하지만, 엑셀에서 수많은 feature들의 경향성을 확인하는 데는 한계가 있다.
첫 번째로 여러 개의 데이터를 순차적으로 그려보기가 어렵다. 여러 칼럼의 데이터를 그래프로 그려보면 하나의 그래프 창에서 섞여서 나타나기 때문이다. 두 번째는 엑셀 그래프에 줌/이동 기능이 없기 때문에 이상 발생 시점의 데이터 경향을 확인하기 위해서는 행의 위치를 파악해 그 부분만 그래프로 그려본다.
1. Matplotlib의 Backend란?
Python에서 가시화를 해주는 몇몇 라이브러리 중 보편적으로 matplotlib을 사용한다. 이번 포스팅에서는 matplotlib으로 기본적인 그래프 그리는 방법을 정리하고 엑셀 그래프에 없는 줌/이동 기능과 subplot을 이용하여 feature 간 상관성을 쉽게 확인해 볼 수 있는 기능을 확인해 보고자 한다.
그래프 생성을 위한 matplotlib과 데이터 처리를 위한 pandas 그리고 파일 경로 확인을 위한 os 라이브러리는 import 하자.
import matplotlib.pyplot as plt
import pandas as pd
import os
%matplotlib qt5
'%matplotlib qt5'는 qt5를 backend로 사용한다고 정의하는 것이다. 만일 초기에 backend 정의를 하지 않으면 셀 단위(vscode, Jupyter의 경우)의 실행 시 그래프는 interactive 창(vscode 기준)에 나타나며 줌/이동 기능을 사용할 수 없다.
일전에는 해당 backend를 사용하면 vscode가 다운되는 현상이 있었다. 최근에는 수정된 듯 하지만 이런 현상이 일어난다면 간단하게 interative 창에서 그래프가 생성되는지 확인하고 전체 실행(Ctrl + F5)을 수행해 별도의 QT창을 띄워야 한다.
2. 데이터 불러와 하나의 그래프 그리기
이제 그래프로 가시화할 데이터를 불러오자. 다른 포스팅에도 언급했듯이 나는 파이썬 파일(ABC.py)이 있는 경로 아래에 'data'폴더를 만들고 그 안에 데이터를 저장하여 사용한다.
file_path = '.\\data\\'
file_name = os.listdir(file_path)
위의 코드에서 data 폴더 내에 있는 모든 파일명을 file_name에 list type으로 갖고 온다. 'test_data.xlsx' 파일 한 개만 저장을 했으나 file_name에는 2개의 파일이 확인된다. 이는 'test_data.xlsx' 파일을 열어보고 있는 경우에 임시로 생성된 파일 때문이다. 열어본 파일을 닫으면 '~$'로 시작하는 파일은 사라지게 된다.
위의 캡처에서 왼쪽 경우와 같이 임시적인 상태에서 for 문을 통해 데이터를 읽어 들이려 한다면(아래 코드 참고) 에러가 발생한다. 물론 파일을 닫고 다시 실행하면 되지만 데이터 확인 차 열어둔 파일을 매번 닫기 번거롭다.
data_list = []
for fn in file_name:
data_list.append(pd.read_excel(file_path + fn))
그냥 한 줄을 원래 코드에 추가하여 파일을 열든 말든 항상 에러가 발생하지 않게 하는 게 가장 깔끔하다. file_name에서 '~'를 포함하고 있지 않는 파일명에 대해서만 read_excel을 실행하게 if문을 추가하였다.
data_list = []
for fn in file_name:
if '~' not in fn:
data_list.append(pd.read_excel(file_path + fn))
위와 같이 data_list를 사용한 이유는 data 폴더 내에 여러 개의 파일이 있을 경우를 대비해서다. 파일이 1개이던 10개이던 모든 파일을 개별의 dataframe으로 불러와서 리스트에 축적해 놓는다.
data = pd.concat(data_list)
data['Time'] = pd.to_datetime(data['Time'])
data_list는 pd.concat을 사용하여 통합시키고, pd.to_datetime으로 string type인 'Time'행의 값을 datetime type으로 변경해 준다. datetime으로 변경시켜주는 이유는 'Time'행을 x축으로 하는 시계열 데이터 가시화를 진행하기 위해서다. 여기까지 가시화할 데이터를 준비했다. 이제 가장 기본적인 방법으로 그래프를 그려보자.
plt.figure()
plt.title(data.columns[1])
plt.plot(data['Time'], data[data.columns[1]])
plt.grid()
plt.show()
matplotlib.pyplot을 plt로 호출하였기에 plt.xxx로 함수들을 사용한다. data.columns는 데이터의 칼럼명들을 list로 만들어 주는데 [0]번은 'Time'이고 그래프는 [1]번 행의 데이터를 이용하여 그리려고 한다. plt.plot(x, y)의 형태이기 때문에 시간을 'x'축에 data['CTP_01']을 y값으로 그래프를 그렸다. grid는 x축과 y축의 주 선을 그려준다.
3. 여러개의 그래프 그리기
이번에는 여러 행의 그래프를 그려보자. 엑셀 안의 데이터는 시간, CTP(Critical to Process, 공정특성) 한 개, 그리고 CTQ(Critical to Quality, 품질특성) 세 개의 칼럼이 존재한다. 공정특성과 품질특성은 품질을 만들어 내는 공정조건과 측정되는 품질의 관계로 이해하면 된다.
이제 subplot을 이용하여 총 4개 항목의 데이터를 가시화해 보자.
plt.figure()
for i in range(1, len(data.columns)):
plt.subplot(len(data.columns)-1, 1, i)
plt.title(data.columns[i])
plt.plot(data['Time'], data[data.columns[i]])
plt.grid()
plt.show()
subplot은 여러 개의 그래프를 하나의 figure 안에 그리게 해 준다. 아래 캡처에서 UI 창의 타이틀을 보면 Figure 2라고 되어 있다. 이는 plt.figure()를 이용하여 2번째 figure가 생성된 걸 의미한다. for 내의 코드를 보면 그래프 하나를 그릴 때와 매우 유사하다. [1] 대신 [i]를 사용하여 for문 내에서 반복하게 만들었다. 위에서는 'Time'을 제외하고는 특정 칼럼명을 사용하지 않고 해당 데이터를 호출했다. 실제로 데이터 내에 어떠한 Feature명이 존재하는지 확인하지 않아도 되는 구문이다.
CTP라는 인자는 CTQ에 영향을 줄 수 있는 데이터다. 왼쪽 4개의 그래프를 보면 중간 부분에서 튀는 현상을 확인할 수 있다. CTP가 튈 때 CTQ도 같이 튄다. 이를 위해 UI 창의 확대 도구를 이용하여 원하는 시간대를 확대해 보았다.
필요한 부분만 확대해서 볼 수 있기 때문에 데이터의 특성을 파악하는데 상당한 도움이 된다. 하지만 4개의 그래프를 확대하기 위해서는 4개 모두 개별적으로 확대를 해줘야 하기 때문에 정확성이 떨어진다. 이를 위해 subplots의 기능을 활용해 보자.
fig, ax = plt.subplots(4, 1, sharex=True)
for i in range(len(ax)):
ax[i].set_title(data.columns[i+1])
ax[i].plot(data['Time'], data[data.columns[i+1]])
ax[i].grid()
plt.show()
그래프를 그리기에 앞서 매번 선언했던 plt.figure()를 사용하지 않고, plt.subplots을 이용하여 fig와 ax라는 객체를 만들었다. subplots안에 (4, 1)로 행이 4개고 열이 1개의 subplot을 정의하였다. sharex 인자를 사용하여 x축을 동기화했다.
plt.title은 ax.set_title로 사용법이 좀 바뀌었고, plt.plot은 ax[i].plot으로 변경되었다. 큰 변화는 없지만 사용법이 직관적이진 않다. 간단하게 설명하자면 plt 사용은 matplotlib의 함수를 직접적으로 사용하는 것이고 ax 사용은 matplotlib의 subplots의 특성을 갖는 새로운 객체를 생성하고 이용하는 것이다.
4. 마치며
포스팅을 하다 보니 또 길어져 버렸다. 항상 초기에는 분량이 적을 거라 생각하고 시작하는데, 정리하다 보면 왜 길어지는지 모르겠다. 암튼 지금까지 분석을 위한 데이터 시각화에 대해 정리해 보았다. 마지막에 객체 생성이라는 내용이 나오는데, 너무 깊게 생각하지 말자. 나도 초기에는 fig, ax 방식이 머리에 들어오지 않아서 plt.figure, plt.plot 만 사용했었다. 최근에는 subplots의 매력에 빠져서 plt 객체에 대해서 공부했으니, 다 이해하려 하지 말고 필요한 것만 그때그때 익히면 된다.