본문 바로가기

데이터/데이터 분석

[혼공] ch 5. 데이터 시각화하기

1. 맷플롯립 기본 요소 알아보기 

 

1) Figure 객체 

 

 

- 맷플롯립에는 Figure라는 모든 그래프 구성 요소를 담고 있는 최상위 객체가 있다. 

- figure() 함수로 명시적으로 피겨 객체를 만들어 활용하면 다양항 그래프 옵션을 조절할 수 있다. 

 

import pandas as pd

ns_book7 = pd.read_csv('ns_book7.csv', low_memory=False)
ns_book7.head()

 

 

 

- 맷플롯립을 임포트한 후 scatter() 함수로 '도서권수'열을 x축, '대출건수'열을 y축으로 그린다. 

- 투명도를 0.1로 지정

 

import matplotlib.pyplot as plt

plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
plt.show()

 

 

 

그래프 크기 바꾸기 : figsize 매개변수 

 

- figure() 함수를 사용하여 피겨 객체를 만들면 그래프 옵션을 조절할 수 있다. 

- figsize 매개변수에 그래프의 크기를 튜플로 지정할 수 있따. 

- 기본 그래프 크기는 (6,4)이고 각각 너비와 높이에 해당, 단위는 인치(inch)

- figsize 매개변수를 (9,6)으로 지정하여 산점도를 좀 더 크게 그리기 

 

plt.figure(figsize=(9, 6))
plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
plt.show()

 

 

 

- plt.show() 함수가 호출되면 figure() 함수로 만들어진 피겨 객체는 자동으로 소멸된다. 

 

그래프 실제 크기 확인하기 

 

- 컴퓨터 화면의 해상도를 말할 때 픽셀 수 와 DPI를 사용한다. 

- DPIdot per inch의 약자로 1인치를 몇 개의 점(픽셀 pixel)으로 표현하는지 나타낸다. 

- DPI에 따라 화면에 그려지는 그래프 크기가 달라진다. 

- figure 매개변수는 인치 단위로 값을 지정해야 한다. 인치 값은 먼저 원하는 픽셀 값을 정한 다음 픽셀 값을 DPI로 나누면 구할 수 있다. 

- 맷플롯립의 DPI 기본값은 72이므로 두 픽셀 값을 72로 나누어 figsize 매개변수에 전달 

 

plt.figure(figsize=(900/72, 600/72))
plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
plt.show()

 

 

 

- 코랩 노트북은 기본적으로 맷플롯립 그래프를 출력할 때 그래프 주변에 공백을 최소화하는 타이트(tight) 레이아웃을 사용한다. 사용하지 않으려면 맷플롯립 그래프를 그릴 때 bbox_inches 옵션을 None으로 지정 

 

%config InlineBackend.print_figure_kwargs = {'bbox_inches': None}
plt.figure(figsize=(900/72, 600/72))
plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
plt.show()

 

 

 

그래프 크기 바꾸기 : dpi 매개변수 

 

- DPI 기본값인 72에서 144로 두배 늘려준다. 

- dpi 매개변수를 두 배로 늘리면 인치당 픽셀 수가 두 배로 늘어나기 떄문에 그래프가 두 배 커진다. 

 

plt.figure(dpi=144)
plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
plt.show()

 

 

 

2) rcParams 객체 

 

- rcParams는 맷플롯립 그래프의 기본값을 관리하는 객체이다. 

- rcParams 객체는 객체에 담긴 값을 출력하는 것뿐만 아니라 새로운 값으로 바꿀 수도 있다. 

 

DPI 기본값 바꾸기 

 

- figure 객체의 DPI 기본값을 100으로 바꾸기 

plt.rcParams['figure.dpi'] = 100

 

 

산점도 마커 모양 바꾸기 

 

- 산점도 그래프의 마커 기본값을 확인하려면 rxParams 객체의 속성을 scatter.marker로 지정 

plt.rcParams['scatter.marker']

 

 

- 마커를 별 모양으로 그리려면 다음과 같이 '*'로 지정 

plt.rcParams['scatter.marker'] = '*'
plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
plt.show()

 

 

- 여러 개의 산점도가 있고, 산점도마다 마커를 다르게 그려야 한다면 매번 scatter.marker 설정을 바꾸는 것은 번거로움 

- 이럴 때는 기본값을 수정하는 대신 scatter()함수의 marker 매개변수로 마커의 모양을 지정하면 된다. 

plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1, marker='+')
plt.show()

 

 

3) 여러 개의 서브플롯 출력하기 

 

- 하나의 피겨 객체 안에는 여러 개의 서브플롯(subplot)을 담을 수 있다. 

- 서브프롯이란 맷플롯립의 Axes 클래스의 객체를 말하며 하나의 서브프롯은 두 개 이상의 축(Axis)을 포함한다. 

- 일반적으로 2차원의 그래프의 수평축을 x축이라 부르고 수직축을 y축으로 부른다. 3차원 그래프라면 세 개의 축이 있다. 

- 각 축에는 눈금 또는 틱(tick)이 표시된다. 또 축의 이름을 나타내는 레이블(label)이 있다. 

 

 

서브플롯 그리기 : subplots() 함수 

 

- 서브플롯을 정의하려면 subplots() 함수에 원하는 서브플롯 개수를 지정하면 된다. 

- subplots() 함수로 두 개의 서브플롯을 그리고 싶다면 매개변수에 2를 넣어주면 된다. 그 다음 이 배열의 원소에서 각각 scatter() 함수와 hist() 함수를 호출한다. 

 

- 첫 번째 그래프인 산점도의 x축은 '도서권수'열이고 y축은 '대출건수'열이다. 

- 두 번째 그래프는 히스토그램으로 x축은 '대출건수'열이고 y축은 대출건수의 빈도에 해당한다. 

- 히스토그램의 y축은 로그 스케일로 지정 

 

fig, axs = plt.subplots(2)

axs[0].scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)

axs[1].hist(ns_book7['대출건수'], bins=100)
axs[1].set_yscale('log')

fig.show()

 

 

- supplots() 함수도 피겨 크기를 지정할 수 있는 figsize 매개변수를 제공한다. 피겨 크기를 (6,8)로 지정하여 높이를 조절

- set_title() 메서드를 사용해서 각 그래프에 제목 넣기 

 

fig, axs = plt.subplots(2, figsize=(6, 8))

axs[0].scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
axs[0].set_title('scatter plot')

axs[1].hist(ns_book7['대출건수'], bins=100)
axs[1].set_title('histogram')
axs[1].set_yscale('log')

fig.show()

 

 

 

서브플롯을 가로로 나란히 출력하기 

 

- subplots() 함수에 행과 열을 지정하면 원하는 서브플롯 개수의 피겨를 만들 수 있다. 

- subplots() 함수의 첫 번째 매개변수는 서브플롯 행의 개수이고 두 번째 매개변수는 열의 개수이다. 

 

- subplots(1,2)와 같이 써서 하나의 행에 두 개의 열을 가진 피겨를 만들기 

- set_title() 메서드로 각 서브플롯의 이름을 지정하고 set_xlabel() 메서드와 set_ylabel()메서드를 사용해 두 서브플로스이 축 이름도 각각 지정 

 

fig, axs = plt.subplots(1, 2, figsize=(10, 4))

axs[0].scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
axs[0].set_title('scatter plot')
axs[0].set_xlabel('number of books')
axs[0].set_ylabel('borrow count')

axs[1].hist(ns_book7['대출건수'], bins=100)
axs[1].set_title('histogram')
axs[1].set_yscale('log')
axs[1].set_xlabel('borrow count')
axs[1].set_ylabel('frequency')

fig.show()

 

 

 

2. 선 그래프와 막대 그래프 그리기 

 

1) 연도별 발행 도서 개수 구하기 

 

- ns_book7 데이터프레임에서 연도별 발행 도서 개수와 주제별 도서 개수 구하기 

 

- 데이터프레임의 한 열에서 value_counts() 메서드를 호출하면 고유한 값의 등장 횟수를 계산한다. 

count_by_year = ns_book7['발행년도'].value_counts()
count_by_year

 

 

- 반환된 count_by_year는 판다스의 시리즈 객체이다. 첫 번째 열이 인덱스이고 두 번째 열이 값에 해당한다. 

- value_counts() 메서드는 기본적으로 값을 기준으로 내림차순으로 정렬 

- count_by_year를 인덱스를 기준으로 오름차순으로 정렬하려면 시리즈 객체의 sort_index() 메서드를 사용하면 됨

 

count_by_year = count_by_year.sort_index()
count_by_year

 

 

- count_by_year 객체에서 index 속성이 2030년보다 작거나 같은 데이터만 뽑기 

count_by_year = count_by_year[count_by_year.index <= 2030]
count_by_year

 

 

 

2) 주제별 도서 개수 구하기 

 

- '주제분류번호'열에는 도서관에서 책을 분류하는 기준인 십진분류 코드가 기입되어 있다. 

- '주제분류번호'열의 첫 번째 문자를 기준으로 도서를 카운트하면 주제별 도서 개수를 구할 수 있다. 

 

- '주제분류번호'열에는 NaN이 포함되어 있으므로 값이 NaN이라면 -1을 반환하는 함수 만들기 

- '주제분류번호'열의 값을 받아 첫 번재 문자를 반환하는 kdc_1st_char() 함수를 선언한 후 apply() 메서드에 넣어 데이터프레임에 반복 적용한다. 

 

import numpy as np

def kdc_1st_char(no):
    if no is np.nan:
        return '-1'
    else:
        return no[0]

count_by_subject = ns_book7['주제분류번호'].apply(kdc_1st_char).value_counts()
count_by_subject

 

 

- 문학에 해당하는 8로 시작하는 도서가 가장 많은 것으로 나타난다. 

 

3) 선 그래프 그리기 

 

- 맷플롯립의 plot() 함수선 그래프를 그릴 수 있다. 첫 번째 매개변수에는 x축의 값, 두 번째 매개변수에는 y축에 해당하는 값을 전달한다. 

 

- 해상도를 높이기 위해 맷플롯립의 기본 DPI를 100으로 바꾼다. 

import matplotlib.pyplot as plt
plt.rcParams['figure.dpi'] = 100

 

- plot() 함수의 두 매개변수에 count_by_year의 연도(index)도서 개수(values)을 각각 지정하여 선그래프를 그린다. 

- 서브플롯을 사용하지 않을 때는 그래프 제목은 title() 함수, x축 이름과 y축 이름은 각각 xlabel() 함수ylabel() 함수를 사용하여 지정한다. 

 

plt.plot(count_by_year.index, count_by_year.values)
plt.title('Books by year')
plt.xlabel('year')
plt.ylabel('number of books')
plt.show()

 

 

 

선 모양과 색상 바꾸기 

 

- plot() 함수는 선 모양을 지정할 수 있는 linestyle 매개변수를 제공한다. 

- linestyle 매개변수 기본값은 실선을 나타내는 '-'dlek. 

 

- color 매개변수에 색상을 지정할 수 있다. #ff000처럼 16진수 컬러 코드를 지정하거나 red처럼 색 이름을 지정할 수 있다. 

- 산점도에서 사용해 보았던 marker 매개변수도 제공한다. 

 

- 마커는 점으로, 선은 점선을 사용한 선 그래프를 빨간색으로 그리기

- 시리즈 객체 그대로 plot() 함수에 전달하면 자동으로 인덱스를 x축의 좌표로 사용하여 그래프를 그린다. 

 

plt.plot(count_by_year, marker='.', linestyle=':', color='red')
plt.title('Books by year')
plt.xlabel('year')
plt.ylabel('number of books')
plt.show()

 

 

 

 

- plot() 함수의 매개변수에 지정한 마커, 선 모양, 색깔을 하나의 문자열로 합쳐서 선 그래프의 포맷으로 나타낼 수도 있다. 

- 이 문자열을 plot() 함수의 x,y축 값 다음에 지정하면 된다. 

plt.plot(count_by_year, '*-g')
plt.title('Books by year')
plt.xlabel('year')
plt.ylabel('number of books')
plt.show()

 

 

 

선 그래프 눈금 개수 조절 및 마커에 텍스트 표시하기 

 

- x축 눈금을 지정할 때는 xticks() 함수를 사용, y축 눈금을 지정할 때는 yticks() 함수를 사용 

- 1947년부터 2030년까지 10년씩 건너뛰면서 x축의 눈금을 표시하기 위해 xticks() 함수 매개변수에 파이썬 range() 함수를 사용한다. 

- 그다음 연도별 발행 도서 개수를 모두 그래프에 표시하면 너무 많기 때문에 슬라이스 연산자(:)를 사용해 다섯 개씩 건너뛰면서 count_by_year 값을 선택한다. 

- 시리즈 객체의 items() 메서드를 사용하면 인덱스와 값을 감싼 튜플을 얻을 수 있다. 

- 그래프에 값을 표시할 때는 annotate() 함수를 사용한다. 첫 번째 매개변수에 그래프에 나타낼 문자열을 지정하고, 두 번째 매개변수에 문자열이 나타날 x,y 좌표를 튜플로 지정한다. 

 

plt.plot(count_by_year, '*-g')
plt.title('Books by year')
plt.xlabel('year')
plt.ylabel('number of books')
plt.xticks(range(1947, 2030, 10))
for idx, val in count_by_year[::5].items():
    plt.annotate(val, (idx, val))
plt.show()

 

 

- annotate() 함수는 기본적으로 마커와 동일한 좌표 시스템을 사용한다. 마커 위치에서 x축은 1만큼,y축으로는 10만큼 떨어지게 지정

 

plt.plot(count_by_year, '*-g')
plt.title('Books by year')
plt.xlabel('year')
plt.ylabel('number of books')
plt.xticks(range(1947, 2030, 10))
for idx, val in count_by_year[::5].items():
    plt.annotate(val, (idx, val), xytext=(idx+1, val+10))
plt.show()

 

 

- x축으로 1만큼 떨어진 것은 구분이 되지만 y축으로 10만큼 떨어뜨린 것은 거의 차이가 없다. 이는 y축의 스케일이 x축보다 훨씬 크기 때문이다. 

 

- 이런 경우에는 상대적인 위치를 포인트나 픽셀 단위로 지정해야 한다. 

- xytext 매개변수와 함께 textcoords 매개변수를 사용한다. 포인트단위의 상대 위치를 나타내는 'offset points'를 지정한다. 

plt.plot(count_by_year, '*-g')
plt.title('Books by year')
plt.xlabel('year')
plt.ylabel('number of books')
plt.xticks(range(1947, 2030, 10))
for idx, val in count_by_year[::5].items():
    plt.annotate(val, (idx, val), xytext=(2, 2), textcoords='offset points')
plt.show()

 

 

 

4) 막대 그래프 그리기 

 

- 맷플롯립에서 bar() 함수는 막대 그래프를 그린다. 

- 주제별 도서 개수인 count_by_subjext를 사용해 막대 그래프 그리기 

- x축에는 인덱스인 주제분류번호, y축에는 도서 개수를 전달한다. 

plt.bar(count_by_subject.index, count_by_subject.values)
plt.title('Books by subject')
plt.xlabel('subject')
plt.ylabel('number of books')
for idx, val in count_by_subject.items():
    plt.annotate(val, (idx, val), xytext=(0, 2), textcoords='offset points')
plt.show()

 

 

텍스트 정렬, 막대 조절 및 색상 바꾸기 

 

- 텍스트 중앙이 막대 중앙에 오도록 중앙정렬

- 텍스트 위치 조절은 annotate() 함수의 ha 매개변수에 'center'를 지정하면 된다. 

- 텍스트가 서로 겹치는 경우가 있으므로 fontsize 매개변수로 텍스트 크기를 줄여준다. 

- 텍스트 색깔도 color 매개변수에 'green'을 지정하여 녹색으로 출력한다. 

 

- bar() 함수는 막대의 두께를 조절하는 width 매개변수를 제공한다. 기본값은 0.8이다. 0.7로 지정하여 막대의 두께를 좀 더 줄여본다. 

- color 매개변수에 'blue'를 지정하여 막대 색깔은 파랑으로 출력한다. 

 

plt.bar(count_by_subject.index, count_by_subject.values, width=0.7, color='blue')
plt.title('Books by subject')
plt.xlabel('subject')
plt.ylabel('number of books')
for idx, val in count_by_subject.items():
    plt.annotate(val, (idx, val), xytext=(0, 2), textcoords='offset points',
                 fontsize=8, ha='center', color='green')
plt.show()

 

 

 

가로 막대 그래프 그리기 

 

- barh() 함수를 사용해 같은 데이터를 가로 막대 그래프로 그리기 

- barh() 함수에서 막대의 두께를 나타내는 매개변수는 width가 아니라 height 매개변수가 된다. 

- 또한, x축과 y축의 이름을 바꾸어 써야 한다. 

- annotate() 함수에 텍스트 좌표를 쓸 때도 x축과 y축의 값이 바뀐다. (val,idx)로 써야 한다. 

 

plt.barh(count_by_subject.index, count_by_subject.values, height=0.7, color='blue')
plt.title('Books by subject')
plt.xlabel('number of books')
plt.ylabel('subject')
for idx, val in count_by_subject.items():
    plt.annotate(val, (val, idx), xytext=(2, 0), textcoords='offset points',
                 fontsize=8, va='center', color='green')
plt.show()

 

 

- 가로 막대 그래프에서 막대 그래프의 텍스트를 중앙에 정렬할 때는 ha 매개변수가 아닌 va 매개변수를 사용한다. 

- 기본값은 'baseline'으로 텍스트 밑면을 막대 중앙에 맞춘다. 

- xytext 매개변수를 (2,0)으로 지정하여 x축 방향으로만 2포인트 간격을 두었다.