나랑 now

[혼공분석] 6주차_복잡한 데이터 표현하기 본문

혼공학습단/혼공분석

[혼공분석] 6주차_복잡한 데이터 표현하기

nowj8n 2024. 2. 12. 15:26
반응형
# 진도 기본 미션 선택 미션
1주차
(1/2 ~ 1/7)
Chapter 01 p. 81의 확인 문제 4번 풀고 인증하기 p. 71 ~ 73 남산 도서관 데이터를 코랩에서 데이터프레임으로 출력하고 화면 캡처하기
2주차
(1/8 ~ 1/14)
Chapter 02 p. 150의 확인 문제 1번 풀고 인증하기 p. 137 ~ 138 손코딩 실습으로 원하는 도서의 페이지 수를 추출하고 화면 캡처하기
3주차
(1/15 ~ 1/21)
Chapter 03 p. 182의 확인 문제 2번 풀고 인증하기 p. 219의 확인 문제 5번 풀고 인증하기
4주차
(1/22 ~ 1/28)
Chapter 04 p. 279의 확인 문제 5번 풀고 인증하기 Ch.04(04-1)에서 배운 8가지 기술통계량(평균, 중앙값, 최솟값, 최댓값, 분위수, 분산, 표준편차, 최빈값)의 개념을 정리하기
5주차
(1/29 ~ 2/4)
Chapter 05 p. 314의 손코딩(맷플롯립에서 bar()함수로 막대 그래프 그리기)을 코랩에서 그래프 출력하고 화면 캡처하기  p. 316의 손코딩(텍스트 정렬, 막대 조절 및 색상 바꾸기)을 코랩에서 출력하고 화면 캡처하기
6주차
(2/5 ~ 2/12)
Chapter 06 p. 344의 손코딩(맷플롯립의 컬러맵으로 산점도 그리기)을 코랩에서 그래프 출력하고 화면 캡처하기 p. 356 ~ 359의 스택 영역 그래프를 그리는 과정을 정리하기

 

 

맷플롯립에는 pyplot 방식과 객체지향 방식 인터페이스가 존재한다.

  • 객체지향 인터페이스
    Figure 또는 Axes 개체를 이용하여 그래프를 그릴 서로 다른 객체(맷플롯립에서는 그래프가 그려지는 객체를 artist라고 표현함)를 만들어 이를 이용해 서로 다른 시각화를 가능하게 하는 인터페이스
    Axes 인터페이스라고도 함
  • pyplot 인터페이스
    생성된 마지막 그림 및 축의 개체에 아티스트를 추가하는 인터페이스

맷플롯립에서는 pyplot 방식을 암시적(implicit)하다고 하며, 명시적(emplicit)인 객체지향 인터페이스를 사용하길 권하고 있다.

단일 그래프를 그리는 경우 pyplot을, 다수의 그래프와 다양한 종류의 그래프를 그리기 위해서는 객체지향 방식을 사용하는 것이 좋다고는 하나, 두 인터페이스의 실질적인 차이는 뭐가 있으며 왜 맷플롯립에서는 객체지향 방식을 선호하는 것일까?

 

단일 그래프를 그리는 경우

pyplot 방식

import matplotlib.pyplot as plt

plt.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
[<matplotlib.lines.Line2D at 0x7c7ae4439e10>]

객체지향 방식

fig = plt.figure()
ax = fig.subplots()
ax.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
[<matplotlib.lines.Line2D at 0x7c7ae44a7820>]

 

아주 간단한 단일 그래프를 그리는 경우, pyplot이 객체지향 방식보다 더 간단해보인다.

하나의 그래프를 그리는 경우, 시각화의 목적이 단순하다면 굳이 figure 객체 안에 subplot을 통해 그래프를 그릴 필요가 없다.

plts = plt.subplots(2,2, figsize=(10,4))
print(plts)	
print(type(plts[1]))

객체지향 방식이 '명시적'인 이유는 맷플롯립은 Figure > Axes > Axies의 구조를 통해 그래프를 그리게 되는데, 지난 주차에서 확인했듯 subplots에 대한 반환값으로 numpy 배열의 ndarray 타입을 받게됨에 따라 이로서 각 axes 객체에 접근하여 다양한 설정이 가능하기 때문.

 

다중 그래프를 그리는 경우

pyplot 방식

plt.subplot(1, 2, 1)
plt.plot([1, 2, 3], [0, 0.5, 0.2])

plt.subplot(1, 2, 2)
plt.plot([3, 2, 1], [0, 0.5, 0.2])
[<matplotlib.lines.Line2D at 0x7c7ae43763b0>]

객체지향 방식

fig, axs = plt.subplots(1, 2)
axs[0].plot([1, 2, 3], [0, 0.5, 0.2])
axs[1].plot([3, 2, 1], [0, 0.5, 0.2])
[<matplotlib.lines.Line2D at 0x7c7abaf77640>]

 

복수의 그래프를 그리는 경우, pyplot도 객체지향 방식과 동일한 그래프를 그릴 수 있는 것처럼 보인다.

그렇다면 같은 결과를 낼 수 있는데도 굳이 왜 객체지향 방식을 사용해야 할까?

우선 pyplot 방식은 코드가 실행되는 순서가 중요한 '절차지향적'이기 때문에 이미 만들어진 객체에 대해 다시 접근하기 위해서는 적절한 위치를 찾아야 한다. subplot을 다시 호출하거나, 해당 객체를 리스트에 저장하는 방법이 있을 수 있다.

plt.subplot(1, 2, 1)
plt.plot([1, 2, 3], [0, 0.5, 0.2])

plt.subplot(1, 2, 2)
plt.plot([3, 2, 1], [0, 0.5, 0.2])

plt.suptitle('Implicit Interface: re-call subplot')

for i in range(1, 3):
    plt.subplot(1, 2, i)
    plt.xlabel('Boo')

axs = []
ax = plt.subplot(1, 2, 1)
axs += [ax]
plt.plot([1, 2, 3], [0, 0.5, 0.2])

ax = plt.subplot(1, 2, 2)
axs += [ax]
plt.plot([3, 2, 1], [0, 0.5, 0.2])

plt.suptitle('Implicit Interface: save handles')

for i in range(2):
    plt.sca(axs[i])
    plt.xlabel('Boo')

 

 

하지만 처음부터 객체지향 방식을 이용하게 되면 원하는 Axes 객체에 접근하기가 쉬우며, 컬러 막대와 같이 Axes로 분류되는 객체로 인한 혼선 없이 그래프를 그릴 수 있게 된다.

 


 

기본 미션

p.344의 손코딩(맷플롯립의 컬러맵으로 산점도 그리기)을 코랩에서 그래프 출력하고 화면 캡처하기

 

선택 미션

p. 356 ~ 359의 스택 영역 그래프를 그리는 과정을 정리하기

스택 그래프는 기본적으로 선 그래프 위에 또 다른 선 그래프를 쌓아 그리는 식으로, 각 그래프가 의미하는 값의 크기(y 값)은 아래 그래프의 y값을 뺀 것이 된다.

 

matplotlib.axes.Axes.stackplot은 필수적으로 x축과 y축에 해당될 데이터를 변수로 입력해야하는데, x의 경우 (N,)과 같은 배열을, y의 경우 (M, N) 형태의 배열을 입력해야한다.

원하는 것은 각 발행년도에 따라 출판사별로 대출건수가 얼마나 되는지를 알고싶은 것이므로 x에는 '발행년도'의 배열을, y에는 '출판사'*'발행년도'로 구성된 2차원 배열 준비하면 된다.

출판사 발행년도 대출건수
민음사 2021 0
김영사 2021 0
문학동네 2021 0
한길사 2021 0
현암사 2021 0

위 데이터를 각 출판사별로 '발행년도'에 따라 테이블 형태를 변경해야하며, 이는 pivot_table() 메서드를 통해 가능하다.

ns_book10 = ns_book9.pivot_table(index='출판사', columns='발행년도')
ns_book10.head()

위 데이터프레임에서 x축으로 보낼 발행년도의 데이터를 판다스의 get_level_values() 메서드를 통해 원하는 열만 가져올 수 있다.

top10_pubs = top30_pubs.index[:10]
year_cols = ns_book10.columns.get_level_values(1)
print(year_cols)

그런데 y 값으로 보낼 데이터프레임에서 결측치(NaN)이 존재하는 것을 확인할 수 있으며, 이 값들을 제거하지 않고 그래프를 그리게 되면 해당 값이 0으로 처리되지 않는다. 따라서 fillna() 메서드로 결측치를 '0'으로 변경해줄 필요가 있다.

fig, ax = plt.subplots(figsize=(8,6))
ax.stackplot(year_cols, ns_book10.loc[top10_pubs].fillna(0), labels=top10_pubs)
ax.set_title('연도별 대출건수')
ax.legend(loc='upper left')
ax.set_xlim(1985, 2025)
fig.show()

 

 

 

참고:

https://matplotlib.org/stable/users/explain/figure/api_interfaces.html 

https://wikidocs.net/14604

반응형