46.4 데이터로 그래프 그리기
csv 파일이 준비되었으니 이제 이 데이터로 그래프를 그려보겠습니다. 앞의 노트북에서 이어서 코드를 작성합니다. 주피터 노트북은 각 코드 셀의 실행 상태가 이어지므로 노트북을 새로 만들 필요 없이 코드 셀을 계속 추가하면서 작성하면 됩니다.
다음은 weather.csv 파일을 읽어서 pandas의 DataFrame 객체로 만듭니다( pandas는 데이터를 처리할 때 사용하는 패키지입니다).
weather.ipynb
# %matplotlib inline을 설정하면 matplotlib.pyplot의 show 함수를 호출하지 않아도 # 주피터 노트북 안에서 그래프가 표시됨 %matplotlib inline import pandas as pd # 데이터를 저장하고 처리하는 패키지 import matplotlib as mpl # 그래프를 그리는 패키지 import matplotlib.pyplot as plt # 그래프를 그리는 패키지 # csv 파일을 읽어서 DataFrame 객체로 만듦. 인덱스 컬럼은 point로 설정 df = pd.read_csv('weather.csv', index_col='point') df # df 표시
실행 결과
--------------------------------------------------------------------------- UnicodeDecodeError Traceback (most recent call last) <ipython-input-4-81f61a36d931> in <module>() 7 8 # csv 파일을 읽어서 DataFrame 객체로 만듦. 인덱스 항목(컬럼)은 point로 설정 ----> 9 df = pd.read_csv('weather.csv', index_col='point') 10 df # df 표시
실행을 해보면 pd.read_csv에서 에러가 발생합니다. 왜냐하면 우리가 가져온 도시별 현재날씨 페이지는 인코딩이 euc-kr로 만들어져 있기 때문입니다.
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr" />
따라서 weather.csv 파일도 인코딩이 euc-kr로 저장됩니다.
이때는 pd.read_csv 함수에 EUC-KR 인코딩을 설정해서 파일을 읽어야 합니다. 다음과 같이 pd.read_csv에 encoding='euc-kr'을 추가합니다.
# csv 파일을 읽어서 DataFrame 객체로 만듦. 인덱스 컬럼은 point로 설정, 인코딩은 euc-kr로 설정 df = pd.read_csv('weather.csv', index_col='point', encoding='euc-kr')
다시 코드 셀을 실행해보면 코드 셀 아래에 표 형태로 변수 df의 값이 표시됩니다. 이렇게 주피터 노트북은 pandas 패키지의 DataFrame을 표 형태로 보여주므로 매우 편리합니다.
데이터를 처리할 때 사용하는 pandas와 그래프를 그리는 matplotlib은 기본적으로 파이썬에 포함되어 있지 않습니다. 따라서 pip install pandas, pip install matplotlib으로 패키지를 설치해줍니다.
pandas의 DataFrame은 엑셀 형태의 자료형인데 컬럼(열)과 로우(행)으로 구성되어 있습니다. 특히 csv 파일의 내용을 별도의 처리 없이 그대로 DataFrame으로 가져올 수 있어서 매우 편리합니다. 단, csv 파일의 첫 줄에는 point,temperature,humidity처럼 컬럼 이름이 들어있어야 합니다.
weather.csv
point,temperature,humidity 서울,25.6,30 백령도,18.4,62 ...생략...
앞에서 pd.read_csv('weather.csv', index_col='point', encoding='euc-kr')와 같이 인덱스 컬럼 index_col에 'point'를 지정해서 각 지점(point)이 맨 왼쪽에 오도록 만들었습니다. 만약 index_col을 지정하지 않으면 맨 왼쪽 컬럼에는 0, 1, 2처럼 숫자 인덱스가 들어갑니다.
46.4.1 특별시 광역시만 모으기
df에 들어있는 지점은 개수가 너무 많아서 그래프로 그리기에는 적합하지 않습니다. 이번에는 df에서 특별시, 광역시만 모아서 따로 DataFrame 객체를 만들어보겠습니다. 코드 셀에서 다음 코드를 실행해보세요.
weather.ipynb
# 특별시, 광역시만 모아서 DataFrame 객체로 만듦 city_df = df.loc[['서울', '인천', '대전', '대구', '광주', '부산', '울산']] city_df # city_df 표시
이렇게 DataFrame의 loc 속성을 이용하면 특정 인덱스의 데이터만 가져올 수 있습니다(loc 속성은 label-location의 약자로 레이블을 지정해 특정 인덱스의 데이터만 가져오는데 쓰입니다).
예를 들어서 loc에 인덱스를 하나만 지정하면 해당 인덱스의 데이터만 가져오고, 인덱스 여러 개를 리스트 형태로 지정하면 DataFrame 형태로 가져옵니다. 이때 인덱스는 문자열로 지정해줍니다.
- DataFrame객체.loc['인덱스']
- DataFrame객체.loc[['인덱스1', '인덱스2']]
>>> df.loc['서울'] temperature 25.6 humidity 30.0 Name: 서울, dtype: float64 >>> df.loc[['서울', '부산']] temperature humidity point 서울 25.6 30 부산 20.2 66
46.4.2 특별시, 광역시만 그래프 그리기
그럼 특별시, 광역시만 들어있는 city_df를 이용해서 그래프를 그려보겠습니다. 코드 셀에서 다음 코드를 실행해보세요(셸이 생기지 않았다면 메뉴의 Insert > Insert Cell Below 실행).
weather.ipynb
# Windows 한글 폰트 설정 font_name = mpl.font_manager.FontProperties(fname='C:/Windows/Fonts/malgun.ttf').get_name() mpl.rc('font', family=font_name) # 차트 종류, 제목, 차트 크기, 범례, 폰트 크기 설정 ax = city_df.plot(kind='bar', title='날씨', figsize=(12, 4), legend=True, fontsize=12) ax.set_xlabel('도시', fontsize=12) # x축 정보 표시 ax.set_ylabel('기온/습도', fontsize=12) # y축 정보 표시 ax.legend(['기온', '습도'], fontsize=12) # 범례 지정
코드 셀을 실행하면 주피터 노트북에서 바로 그래프가 그려집니다. 각 특별시, 광역시의 기온과 습도를 막대 그래프로 확인할 수 있습니다.
이렇게 matplotlib 패키지로 pandas의 DataFrame을 그래프로 그릴 수 있습니다.
46.4.3 소스 코드 살펴보기
이제 코드를 살펴보겠습니다. matplotlib은 기본적으로 그래프에서 한글 표시가 안 됩니다. 그래서 다음과 같이 mpl.font_manager.FontProperties에 C:/Windows/Fonts/malgun.ttf를 지정하여 맑은 굴림 폰트(malgun.ttf)의 정보를 가져온 뒤 get_name으로 폰트 이름을 얻습니다. 그다음에 mpl.rc('font', family=font_name)과 같이 폰트 설정을 해주면 됩니다.
# Windows 한글 폰트 설정 font_name = mpl.font_manager.FontProperties(fname='C:/Windows/Fonts/malgun.ttf').get_name() mpl.rc('font', family=font_name)
macOS에서 한글 폰트를 설정하려면 mpl.rc에 family='AppleGothic'을 지정해주면 됩니다.
# macOS 한글 폰트 설정 mpl.rc('font', family='AppleGothic')
46.4.4 plot 메서드로 그래프 그리기
DataFrame 객체로 그래프를 그릴 때는 plot 메서드를 사용합니다. 우리는 기온, 습도를 막대 그래프(바 차트)로 그릴 것이므로 차트 종류 kind에 'bar'를 지정해줍니다. 그리고 차트 제목 title에는 '날씨', 차트 크기 figsize에는 (12, 4), 범례 legend에는 True, 폰트 크기 fontsize에는 12를 지정해줍니다.
# 차트 종류, 제목, 차트 크기, 범례, 폰트 크기 설정 ax = city_df.plot(kind='bar', title='날씨', figsize=(12, 4), legend=True, fontsize=12)
city_df에서 plot 메서드를 사용하면 축 서브플롯( AxesSubplot) 객체가 나옵니다(plot은 그래프를 그리다라는 뜻). 이 객체에서 set_xlabel 메서드를 사용하여 x축 정보를 표시하고, set_ylabel 메서드를 사용하여 y축 정보를 표시합니다.
ax.set_xlabel('도시', fontsize=12) # x축 정보 표시 ax.set_ylabel('기온/습도', fontsize=12) # y축 정보 표시
그리고 legend 메서드에 범례를 리스트 형태로 넣어줍니다(범례는 차트의 각 막대가 무슨 값인지 표시해줍니다). 여기서는 city_df의 컬럼이 temperature, humidity 순으로 되어있므로 ['기온', '습도']와 같이 넣어줍니다.
ax.legend(['기온', '습도'], fontsize=12) # 범례 지정
지금까지 기상청의 도시별 현재날씨 페이지를 가져와서 그래프로 그려보았습니다. pandas와 matplotlib은 내용이 복잡하고 방대해서 초보자들은 다루기가 쉽지 않습니다. pandas와 matplotlib을 제대로 사용하려면 이 라이브러리를 다룬 전문 서적을 봐야 하지만 여기서는 필요한 것만 사용해서 실습해봤습니다. 일단은 파이썬에서 이런 것도 된다 정도만 알고 넘어가도 됩니다. 나중에 파이썬에 익숙해지면 복잡한 그래프도 그릴 수 있게 됩니다. 특히 주피터 노트북은 pandas, matplotlib을 학습할 때 매우 효과적이므로 적극 활용하기 바랍니다.
주피터 노트북에서 %matplotlib inline 설정을 해주면 matplotlib.pyplot의 show 함수를 호출하지 않아도 주피터 노트북 안에서 그래프가 표시됩니다.
만약 %matplotlib inline를 지정하지 않았거나 IDLE, 파이썬 인터프리터에서 그래프를 표시하려면 matplotlib.pyplot의 show 함수 호출하면 됩니다.
plt.show() # %matplotlib inline을 지정하지 않았거나 IDLE, 파이썬 인터프리터에서 # 그래프를 표시하려면 matplotlib.pyplot의 show 함수 호출
pandas 및 DataFrame은 기능이 매우 많아서 모두 설명하려면 책 한 권으로도 부족합니다. 여기서는 DataFrame의 기본 기능만 설명하겠습니다. 다음과 같이 DataFrame 객체에 컬럼 이름만 지정하면 컬럼에 해당하는 값을 모두 가져올 수 있습니다. 컬럼 이름은 [ ](대괄호)에 인덱스를 지정해도 되고, 속성으로 접근해도 됩니다.
DataFrame객체['컬럼이름']
DataFrame객체.컬럼이름
다음은 기온 temperature 컬럼에 해당하는 모든 값을 가져옵니다.
>>> city_df['temperature'] point 서울 25.6 인천 20.8 대전 25.1 대구 25.7 광주 24.0 부산 20.2 울산 19.7 Name: temperature, dtype: float64 >>> city_df.temperature point 서울 25.6 인천 20.8 대전 25.1 대구 25.7 광주 24.0 부산 20.2 울산 19.7 Name: temperature, dtype: float64
그럼 기온이 가장 높은 도시와 낮은 도시를 가져와보겠습니다. 다음과 같이 DataFrame 객체에서 temperature 컬럼의 값들을 가져온 뒤 idxmax 메서드를 사용하면 가장 높은 값의 인덱스가 나오며 idxmin 메서드를 사용하면 가장 낮은 값의 인덱스가 나옵니다.
>>> city_df.temperature.idxmax() '대구' >>> city_df.temperature.idxmin() '울산'
조금 응용해서 idxmax와 idxmin의 결과를 DataFrame 객체의 loc에 지정하면 인덱스(지점, 도시)에 해당하는 행을 가져올 수 있습니다.
>>> city_df.loc[city_df.temperature.idxmax()] temperature 25.7 humidity 31.0 Name: 대구, dtype: float64 >>> city_df.loc[city_df.temperature.idxmin()] temperature 19.7 humidity 70.0 Name: 울산, dtype: float64