47.4 데이터로 그래프 그리기

데이터가 준비되었으니 이제 데이터로 그래프를 그려보겠습니다. 앞의 노트북에서 이어서 코드를 작성합니다. 주피터 노트북은 각 코드 셀의 실행 상태가 이어지므로 노트북을 새로 만들 필요 없이 코드 셀을 계속 추가하면서 작성하면 됩니다.

그럼 코드 셀에서 다음 코드를 실행합니다.

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로 만들어져 있기 때문입니다. 따라서 weather.csv 파일도 인코딩이 euc-kr로 저장됩니다.

<meta http-equiv="Content-Type" content="text/html; charset=euc-kr" />

이때는 pd.read_csv 함수에 인코딩을 설정해줍니다. 다음과 같이 pd.read_csvencoding='euc-kr'을 추가합니다.

# csv 파일을 읽어서 DataFrame 객체로 만듦. 인덱스 컬럼은 point로 설정, 인코딩은 euc-kr로 설정
df = pd.read_csv('weather.csv', index_col='point', encoding='euc-kr')

다시 코드 셀을 실행해보면 코드 셀 아래에 표 형태로 변수 df의 값이 표시됩니다. 이렇게 주피터 노트북은 pandas 패키지의 DataFrame을 표 형태로 보여주므로 매우 편리합니다.

그림 47-20 csv 파일을 읽은 뒤 DataFrame 표시
그림 47 20 csv 파일을 읽은 뒤 DataFrame 표시

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처럼 숫자 인덱스가 들어갑니다.

이제 소스 코드를 살펴보겠습니다. 여기서는 pandas 모듈로 데이터를 저장, 처리하며 matplotlib 모듈로 그래프를 그립니다(보통 pandaspd, matplotlibmpl, matplotlib.pyplotplt로 줄여서 사용합니다). 그리고 %matplotlib inline 설정을 해주면 matplotlib.pyplotshow 함수를 호출하지 않아도 주피터 노트북 안에서 그래프가 표시됩니다.

# %matplotlib inline을 설정하면 matplotlib.pyplot의 show 함수를 호출하지 않아도
# 주피터 노트북 안에서 그래프가 표시됨
%matplotlib inline
import pandas as pd                # 데이터를 저장하고 처리하는 모듈
import matplotlib as mpl           # 그래프를 그리는 모듈
import matplotlib.pyplot as plt    # 그래프를 그리는 모듈
참고 | 아나콘다를 사용하지 않는다면?

pandasmatplotlib은 기본적으로 파이썬에 포함되어 있지 않습니다. 따라서 pip install pandas, pip install matplotlib으로 패키지를 설치해줍니다.

각 모듈을 가져왔으면 pandasread_csv로 csv 파일을 읽어서 DataFrame 객체로 만듭니다. 그리고 인덱스 컬럼은 'point'로 설정해주고, 인코딩은 'euc-kr'로 설정합니다.

# csv 파일을 읽어서 DataFrame 객체로 만듦. 인덱스 컬럼은 point로 설정, 인코딩은 euc-kr로 설정
df = pd.read_csv('weather.csv', index_col='point', encoding='euc-kr')
df    # df 표시

df에 들어있는 지점은 개수가 너무 많아서 그래프로 그리기에는 적합하지 않습니다. 이번에는 df에서 특별시, 광역시만 모아서 따로 DataFrame 객체를 만들어보겠습니다. 코드 셀에서 다음 코드를 실행해보세요.

weather.ipynb

# 특별시, 광역시만 뽑아서 DataFrame 객체로 만듦
city_df = df.loc[['서울', '인천', '대전', '대구', '광주', '부산', '울산']]
city_df    # city_df 표시

이렇게 DataFrameloc 속성을 이용하면 특정 인덱스의 데이터만 가져올 수 있습니다.

그림 47-21 특별시
그림 47 21 특별시, 광역시만 뽑아서 DataFrame 객체로 만듦

예를 들어서 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

그럼 특별시, 광역시만 들어있는 city_df를 이용해서 그래프를 그려보겠습니다. 코드 셀에서 다음 코드를 실행해보세요.

weather.ipynb

# 한글 폰트 설정
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)    # 범례 지정

코드 셀을 실행하면 주피터 노트북에서 바로 그래프가 그려집니다. 각 특별시, 광역시의 기온과 습도를 막대 그래프로 확인할 수 있습니다.

그림 47-22 DataFrame으로 그래프 그리기
그림 47 22 DataFrame으로 그래프 그리기

이제 코드를 살펴보겠습니다. matplotlib은 기본적으로 그래프에서 한글 표시가 안 됩니다. 그래서 다음과 같이 mpl.font_manager.FontPropertiesC:/Windows/Fonts/malgun.ttf을 지정하여 맑은 굴림 폰트(malgun.ttf)의 정보를 가져온 뒤 get_name으로 폰트 이름을 얻습니다. 그다음에 mpl.rc('font', family=font_name)과 같이 폰트 설정을 해주면 됩니다.

# 한글 폰트 설정
font_name = mpl.font_manager.FontProperties(fname='C:/Windows/Fonts/malgun.ttf').get_name()
mpl.rc('font', family=font_name)

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축 정보를 표시합니다. 그리고 legend 메서드에 범례를 리스트 형태로 넣어줍니다(범례는 차트의 각 막대가 무슨 값인지 표시해줍니다). 여기서는 city_df의 컬럼이 temperature, humidity 순으로 되어있므로 ['기온', '습도']와 같이 넣어줍니다.

ax.set_xlabel('도시', fontsize=12)          # x축 정보 표시
ax.set_ylabel('기온/습도', fontsize=12)     # y축 정보 표시
ax.legend(['기온', '습도'], fontsize=12)    # 범례 지정

참고로 %matplotlib inline를 지정하지 않았거나 IDLE, 파이썬 인터프리터에서 그래프를 표시하려면 matplotlib.pyplotshow 함수 호출하면 됩니다.

plt.show()    # %matplotlib inline을 지정하지 않았거나 IDLE, 파이썬 인터프리터에서
              # 그래프를 표시하려면 matplotlib.pyplot의 show 함수 호출

지금까지 기상청의 도시별 현재날씨 페이지를 가져와서 그래프로 그려보았습니다. pandasmatplotlib은 내용이 복잡하고 방대해서 초보자들은 다루기가 쉽지 않습니다. 그래서 이번 유닛에서는 최대한 간단하게 실습을 해보았습니다. 일단은 파이썬이 이런 것도 된다 정도만 알고 넘어가도 됩니다. 나중에 파이썬에 익숙해지면 복잡한 그래프도 그릴 수 있게 됩니다. 특히 주피터 노트북은 pandas, matplotlib을 학습할 때 매우 효과적이므로 적극 활용하기 바랍니다.

참고 | DataFrame 사용하기

pandasDataFrame은 기능이 매우 많아서 모두 설명하려면 책 한 권으로도 부족합니다. 여기서는 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 컬럼의 값들을 가져온 뒤 argmax 메서드를 사용하면 가장 높은 값의 인덱스가 나오며 argmin 메서드를 사용하면 가장 낮은 값의 인덱스가 나옵니다.

>>> city_df.temperature.argmax()
'대구'
>>> city_df.temperature.argmin()
'울산'

조금 응용해서 argmaxargmin의 결과를 DataFrame 객체의 loc에 지정하면 인덱스(지점, 도시)에 해당하는 행을 가져올 수 있습니다.

>>> city_df.loc[city_df.temperature.argmax()]
temperature    25.7
humidity       31.0
Name: 대구, dtype: float64
>>> city_df.loc[city_df.temperature.argmin()]
temperature    19.7
humidity       70.0
Name: 울산, dtype: float64