# 9.2부터 복습함
9장 그래프와 시각화¶
9.1 matplotlib API 간략히 살펴보기¶
import matplotlib.pyplot as plt
import numpy as np
data = np.arange(10)
data
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
plt.plot(data)
[<matplotlib.lines.Line2D at 0x181f8cd2fb0>]
9.1.1 figure와 서브플롯¶
plt.figure¶
matplotlib에서 그래프는 Figure 객체 내에 존재
그래프를 위한 새로운 figure(피겨)는 plt.figure을 사용해 생성
fig = plt.figure()
<Figure size 640x480 with 0 Axes>
add_subplot¶
빈 figure로는 그래프를 그릴 수 없음
add_subplot을 사용해 최소 하나 이상의 subplots를 생성해야 함
ax1 = fig.add_subplot(2,2,1)
위 코드는 figure가 2x2 크기이고 4개의 서브플롯 중에서 첫 번째를 선택하겠다는 의미(서브플롯은 1부터 숫자가 매겨짐)
다음처럼 2개의 서브플롯을 더 추가해보자
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)
fig
*TIP* 주피터 노트북을 사용할 때는 실행되는 셀마다 그래프가 리셋됨.
따라서 복잡한 그래프를 그릴 때는 단일 노트북 셀에 그래프를 그리는 코드를 모두 입력
여기서는 아래 코드를 모두 같은 셀에서 실행함
fig = plt.figure()
ax2 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax2 = fig.add_subplot(2,2,3)
plt.plot([1.5, 3.5, -2, 1.6])¶
plt.plot([1.5, 3.5, -2, 1.6]) 명령으로 그래프를 띄우면 matplotlib는 가장 최근의 figure와 그 서브플롯을 그림
서브플롯이 없다면 서브플롯 하나를 생성. 이렇게 해서 figure와 서브플롯이 생성되는 과정을 숨겨줌
plt.plot([1.5, 3.5, -2, 1.6])
[<matplotlib.lines.Line2D at 0x181f8c12ef0>]
fig = plt.figure()
ax2 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax2 = fig.add_subplot(2,2,3)
plt.plot(np.random.randn(50).cumsum(), 'k--')
[<matplotlib.lines.Line2D at 0x181f909c460>]
k--¶
'k--' 옵션은 검은 점선을 그리기 위한 *스타일* 옵션
fig.add_subplot에서 반환되는 객체는 AxesSubplot인데, 각각의 인스턴스 메서드를 호출해서 다른 빈 서브플롯에 직접 그래프 그리기 가능
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)
plt.plot(np.random.randn(50).cumsum(), 'k--')
_ = ax1.hist(np.random.rand(100), bins = 20, color='k', alpha = 0.3)
ax2.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30))
<matplotlib.collections.PathCollection at 0x181f91a9960>
plt.subplots¶
특정한 배치에 맞추어 여러 개의 서브플롯을 포함하는 figure을 생성하는 일은 흔히 접하게 되는 업부인데 이를 위한 plt.subplots라는 편리한 메서드가 있다.
이 메서드는 NumPy 배열과 서브플롯 객체를 새로 생성해 반환
fig, axes = plt.subplots(2,3)
axes 배열은 axes[0,1]처럼 2차원 배열로 쉽게 색인될 수 있어서 편리하게 사용가능
서브플롯이 같은 x축 혹은 y축을 가져야 한다면 각각 sharex와 sharey를 사용해 지정 가능
같은 범위 내에서 데이터를 비교해야 할 경우 특히 유용
그렇지 않으면 matplotlib은 각 그래프의 범위를 독립적으로 조정
pyplot.subplots 옵션¶
353쪽 참고
서브플롯 간의 간격 조절하기¶
matplotlib은 서브플롯 간에 적당한 간격(spacing)과 여백(padding)을 추가해줌
subplots_adjust¶
서브플롯 간의 간격은 Figure 객체의 subplots_adjust 메서드를 사용해 쉽게 바꿀 수 있음
subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None hspace=None)
Cell In[202], line 1 subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None hspace=None) ^ SyntaxError: invalid syntax. Perhaps you forgot a comma?
wspace, hspace¶
wspace와 hspace는 서브플롯 간의 간격을 위해 각각 figure의 너비와 높이에 대한 비율 조절
다음 코드는 서브플롯 간의 간격을 주지 않은 그래프를 생성하는 코드
fig, axes = plt.subplots(2,2, sharex=True, sharey=True)
for i in range(2):
for j in range(2):
axes[i,j].hist(np.random.randn(500), bins=50, color='k', alpha=0.5)
plt.subplots_adjust(wspace=0,hspace=0)
그래프를 그렸을 때 축 이름이 겹치는 경우가 있다.
matplotlib은 그래프에서 이름이 겹치는지 검사하지 않기 때문에 이와 같은 경우에는 눈금 위치와 눈금 이름을 명시적으로 직접 지정
다음 절에서 알아보자
9.1.2 색상, 마커, 선 스타일¶
matplotlib에서 가장 중요한 plot 함수는 x와 y 좌푯값이 담긴 배열과 추가적으로 색상과 선스타일을 나타내는 축약 문자열을 인자로 받음
예를 들어 녹색 점선으로 그려진 x 대 y 그래프는 아래처럼 나타냄
ax.plot(x, y, 'g--')
위에서 만든 그래프는 아래처럼 좀 더 명시적인 방법으로 표현 가능
ax.plot(x, y, linestyle='--', color='g')
마커¶
선그래프는 특정 지점의 실제 데이터를 돋보이게 하기 위해 *마커*를 추가하기도 함
마커도 스타일 문자열에 포함시킬 수 있는데 색상 다음에 마커 스타일이 오고 그 뒤에 선 스타일 지정
from numpy.random import randn
plt.plot(randn(30).cumsum(), 'ko--')
이 역시 좀 더 명시적인 방법으로 표현 가능
plot(randn(30).cumsum(), color='k', linestyle='dashed', marker='o')
선그래프를 보면 일정한 간격으로 연속된 지점이 연결되어 있다
이 역시 drawstyle옵션을 이용해 바꿀 수 있다
data = np.random.randn(30).cumsum()
plt.plot(data, 'k--', label='Default')
plt.plot(data, 'k-', drawstyle='steps-post', label='steps-post')
data = np.random.randn(30).cumsum()
plt.plot(data, 'k--', label='Default')
plt.plot(data, 'k-', drawstyle='steps-post', label='steps-post')
plt.legend(loc='best')
9.1.3 눈금, 라벨, 범례¶
그래프를 꾸미는 방법 2가지
- pyplot 인터페이스를 사용해 순차적으로 꾸미기(즉, matplotlib.pyplot)
- matplotlib이 제공하는 API를 사용해 좀 더 객체지향적인 방법으로 꾸미기
pyplot 인터페이스는 대화형 사용에 맞추어 설계되었으며 xlim, xticks, xticklabels 같은 메서드로 이루어짐
이런 메서드로 표의 범위를 지정하거나 눈금 위치, 눈금 이름을 조절 가능
- 아무런 인자 없이 호출하면 현재 설정되어 있는 매개변수의 값을 반환. plt.xlim 메서드는 현재 x 축의 범위 반환
- 인자를 전달하면 매개변수의 값 설정. 예를 들어 plt.xlim([0,10])을 호출하면 x축의 범위가 0부터 10까지로 설정
이 모든 메서드는 현재 활성화된 혹은 가장 최근에 생성된 AxesSubplot 객체에 대해 동작
위에서 소개한 모든 메서드는 서브플롯 객체의 set/get 메서드로도 존재하는데,
xlim이라하면 ax.get_xlim과 ax.set_xlim 메서드가 존재
제목, 축 이름, 눈금, 눈금 이름 설정하기¶
무작위 값으로 그래프 생성
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum())
set_xticks, set_xticklabels¶
x축의 눈금을 변경하기 위한 가장 쉬운 방법은 set_xticks와 set_xticklabels 메서드 사용하기
set_xsticks 메서드는 전체 데이터 범위를 따라 눈금을 어디에 배치할지 지정
기본적으로 이 위치에 눈금 이름이 들어감
다른 눈금 이름을 지정하고 싶다면 set_xticklabels 사용
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum())
ticks = ax.set_xticks([0, 250, 500, 750, 1000])
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum())
ticks = ax.set_xticks([0, 250, 500, 750, 1000])
labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'], rotation=30, fontsize='small')
set_xlabel, set_title¶
마지막으로 set_xlabel 메서드는 x축에 대한 이름을 지정하고 set_title 메서드는 서브플롯의 제목을 지정
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(np.random.randn(1000).cumsum())
ticks = ax.set_xticks([0, 250, 500, 750, 1000])
labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'], rotation=30, fontsize='small')
ax.set_title('My first matplotlib plot')
ax.set_xlabel('Stages')
x대신 y를 써서 같은 과정을 y축에 대해 진행
axes 클래스는 플롯의 속성을 설정할 수 있도록 set 메서드 제공
위 예제는 아래와 같이 작성도 가능
props = {
'title': 'My first matplotlib plot',
'xlabel':'Stages'
}
ax.set(**props)
범례 추가하기¶
범례를 추가하는 가장 쉬운 방법은 각 그래프에 label 인자 넘기기
label¶
from numpy.random import randn
fig = plt.figure();
ax = fig.add_subplot(1,1,1)
ax.plot(randn(1000).cumsum(), 'k', label='one')
ax.plot(randn(1000).cumsum(), 'k--', label='two')
ax.plot(randn(1000).cumsum(), 'k.', label='three')
ax.legend(), plt.legend()¶
이렇게 하면 ax.legend()나 plt.legend()를 실행했을 때 자동으로 범례 생성
from numpy.random import randn
fig = plt.figure();
ax = fig.add_subplot(1,1,1)
ax.plot(randn(1000).cumsum(), 'k', label='one')
ax.plot(randn(1000).cumsum(), 'k--', label='two')
ax.plot(randn(1000).cumsum(), 'k.', label='three')
ax.legend(loc='best')
legend 메서드는 범례 위치를 지정하기 위한 loc 인자 제공
legend 메서드의 문서에서 더 자세한 정보 확인
ax.legend?
loc¶
loc는 범례를 그래프에서 어디에 위치시킬지 지정해주는 인자
'best'는 최대한 방해가 되지 않는 곳에 위치시킴
범례에서 제외하고 싶은 요소가 있다면 label 인자를 넘기지 않거나 label='nolegend' 옵션 사용
9.1.4 주석과 그림 추가¶
주석과 글자는 text, arrow, annotate 함수를 이용해 추가
text 함수는 그래프 내의 주어진 좌표 (x,y)에 부가적인 스타일로 글자를 그려줌
ax.text(x,y, 'Hello world!',
family='monospace', fontsize=10)
주석은 글자와 화살표를 함께 써서 그릴 수 있는데,
예를 들어 야후!파이낸스에서 얻은 2007년부터의 S&P 500 지수 데이터로 그래프를 생성하고 2008-2009년 사이에 있었던 재정위기 중 중요한 날짜를 주석으로 추가해보자
- set_xlim 오류 참고
from datetime import datetime
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
data = pd.read_csv('spx.csv', index_col=0, parse_dates=True)
spx = data['SPX']
spx.plot(ax=ax, style='k-')
crisis_data = [
(datetime(2007, 10, 11), 'Peak of bull market'),
(datetime(2008, 3, 12), 'Bear Stearns Fails'),
(datetime(2008, 9, 15), 'Lehman Bankruptcy')
]
for date, label in crisis_data:
ax.annotate(label, xy=(date, spx.asof(date) + 75),
xytext=(date, spx.asof(date) + 225),
arrowprops = dict(facecolor='black', headwidth=4, width=2,
headlength=4),
horizontalalignment='left', verticalalignment='top')
#2007-2010 구간으로 확대
ax.set_xlim([pd.to_datetime('1/1/2007', format = '%d/%m/%Y'),
pd.to_datetime('1/1/2011', format = '%d/%m/%Y')])
ax.set_ylim(([600, 1800]))
ax.set_title('Important dates in the 2008-2009 financial crisis')
ax.annotate : x,y 좌표로 지정한 위치에 라벨 추가
set_xlim, set_ylim : 그래프의 시작 끝 경계를 직접 지정
ax.set_title : 그래프의 제목 지정
add_patch¶
matplotlib은 일반적인 도형을 표현하기 위한 patches라는 객체 제공
그래프에 도형을 추가하려면 patches 객체인 shp를 만들고 서브플롯에 ax.add_patch(shp) 호출
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
rect = plt.Rectangle((0.2, 0.75), 0.4, 0.15, color='k', alpha=0.3)
circ = plt.Circle((0.7, 0.2), 0.15, color='b', alpha=0.3)
pgon = plt.Polygon([[0.15, 0.15], [0.35, 0.4], [0.2, 0.6]],
color='g', alpha=0.5)
ax.add_patch(rect)
ax.add_patch(circ)
ax.add_patch(pgon)
9.1.5 그래프를 파일로 저장¶
plt.savefig¶
활성화된 figure은 plt.savefig 메서드를 이용해 파일로 저장
이 메서드는 figure 객체의 인스턴스 메서드인 savefig와 동일
figure를 SVG 포맷으로 저장하려면 다음과 같이
plt.savefig('figpath.svg')
출판용 그래픽 파일 생성 시 사용하는 중요한 옵션
- dpi : 인치당 도트 해상도 조절
- bbox_inches : 실체 figure 둘레의 공백을 잘라냄
그래프 간 최소 공백을 가지는 400DPI짜리 PNG 파일 만들기
plt.savefig('figpath.png', dpi=400, bbox_inches='tight')
savefig 메서드는 파일에 저장할 뿐만 아니라 BytesIO처럼 파일과 유사한 객체에 저장도 가능
from io import BytestIO
buffer = BytesIO()
plt.savefig(buffer)
plot_data = buffer.getvalue()
Figure.savefig 옵션¶
p.364확인
9.1.6 matplotlib 설정¶
matplotlib의 환경 설정 시스템은 두 가지 방법으로 나눌 수 있는데, 첫 번째는 rc 메서드를 사용해 프로그래밍적으로 설정
예를 들어 figure의 크기를 10x10으로 전역 설정
plt.rc('figure', figsize=(10,10))
rc 메서드의 첫 번째 인자 : 설정하고자 하는 'figure', 'axes', 'xtick', 'ytick', 'grid','legend' 및 다른 컴포넌트의 이름
그 다음 인자: 설정할 값에 대한 키워드 인자
이 옵션을 쉽게 작성하려면 파이썬의 사전 타입 사용
font_options = {'family': 'monospace',
'weight':'bold',
'size':'small'}
plt.rc('font', **font_options)
9.2 pandas에서 seaborn으로 그래프 그리기¶
9.2.1 선그래프¶
plot¶
Series와 DataFrame 둘 다 plot 메서드를 이용해 다양한 형태의 그래프 생성
기본적으로 plot 메서드는 선그래프 생성
s = pd.Series(np.random.randn(10).cumsum(), index = np.arange(0,100,10))
s.plot()
<Axes: >
Series 색체의 색인은 matplotlib에서 그래프 생성 시 x축으로 해석되며
use_index=False 옵션을 넘겨서 그래프의 축으로 사용하는 것을 막을 수 있음
x축의 눈금과 한계 : xticks와 xlim 옵션으로 조절
y축 : yticks와 ylim
대부분의 pandas 그래프 메서드는 부수적으로 ax 인자를 받는데, 이 인자는 matplotlib의 서브플롯 객체가 될 수 있음
이를 이용해 그리드 배열 상에서 서브플롯의 위치를 좀 더 유연하게 가져갈 수 있음
DataFrame의 plot 메서드는 하나의 서브플롯 안에 각 컬럼별로 선그래프를 그리고 자동적으로 범례 생성
df = pd.DataFrame(np.random.randn(10,4).cumsum(0),
columns = ['A', 'B', 'C', 'D'],
index=np.arange(0,100,10))
df
A | B | C | D | |
---|---|---|---|---|
0 | 1.061752 | 0.446843 | 1.333358 | -0.277268 |
10 | 0.555583 | 1.765282 | 1.112763 | -0.261158 |
20 | 1.120806 | 0.757018 | 0.981720 | -0.474901 |
30 | 0.349458 | 0.000310 | 2.067122 | -1.138440 |
40 | -0.047521 | 0.103790 | 2.578885 | -0.816331 |
50 | 0.222224 | -0.898479 | 0.879471 | -1.503545 |
60 | 0.944954 | -1.765227 | -1.094624 | -1.424960 |
70 | 1.122581 | -1.216755 | -1.864021 | -1.182704 |
80 | 2.996640 | 1.665431 | -2.007931 | -1.180902 |
90 | 1.950724 | 1.311996 | -1.676890 | -4.392413 |
df.plot()
<Axes: >
df.plot()은 df.plot.line()과 동일
Series.plot 메서드 인자¶
368참고
DataFrame의 plot 메서드 인자¶
368확인
9.2.2 막대그래프¶
plot.bar(), plot.barh()¶
plot.bar()과 plot.barh()는 각각 수직막대그래프와 수평막대그래프를 그림
이 경우 Series 또는 DataFrame의 색인은 수직막대그래프(bar)인 경우 x 눈금,
수평막대그래프(barh)인 경우 y눈금으로 사용
fig, axes = plt.subplots(2,1)
data = pd.Series(np.random.rand(16), index=list('abcdefghijklmnop'))
data
a 0.379750 b 0.729424 c 0.256979 d 0.352572 e 0.561537 f 0.601787 g 0.337636 h 0.229199 i 0.567849 j 0.448571 k 0.131688 l 0.314704 m 0.040275 n 0.524845 o 0.313289 p 0.530071 dtype: float64
fig, axes = plt.subplots(2,1)
data = pd.Series(np.random.rand(16), index=list('abcdefghijklmnop'))
data.plot.bar(ax=axes[0], color='k', alpha=0.7)
<Axes: >
fig, axes = plt.subplots(2,1)
data = pd.Series(np.random.rand(16), index=list('abcdefghijklmnop'))
data.plot.bar(ax=axes[0], color='k', alpha=0.7)
data.plot.barh(ax=axes[1], color='k', alpha=0.7)
<Axes: >
color='k' 옵션과 alpha=0.7 옵션은 그래프를 검은색으로 그리고 투명도 지정
*NOTE_* 막대그래프를 그릴 때 유용한 방법 : Series의 value_counts 메서드(s.value_counts().plot.bar())를 이용해 값의 빈도 그리기
DataFrame에서 막대그래프는 각 로우의 값을 함께 묶어서 하나의 그룹마다 각각의 막대를 보여줌
df = pd.DataFrame(np.random.randn(6,4),
index=['one', 'two', 'three', 'four', 'five', 'six'],
columns = pd.Index(['A', 'B', 'C', 'D'], name='Genius'))
df
Genius | A | B | C | D |
---|---|---|---|---|
one | -0.860384 | -0.698648 | 0.932524 | 1.012765 |
two | 0.750711 | -0.491572 | -0.116640 | -0.337020 |
three | 0.944171 | 0.820391 | 2.111688 | 1.039145 |
four | 2.072118 | 1.201615 | 1.237838 | -1.420203 |
five | -0.119483 | -0.146839 | -1.565368 | 0.554560 |
six | -0.145386 | -2.005226 | 1.271194 | -0.739267 |
df.plot.bar()
<Axes: >
stacked=True¶
누적막대그래프는 stacked=True 옵션을 사용해 생성할 수 있는데, 각 로우의 값들이 하나의 막대에 누적되어 출력
df.plot.barh(stacked=True, alpha=0.5)
<Axes: >
tips 데이터에서 요일별 파티 숫자를 뽑고 파티 숫자 대비 팁 비율을 보여주는 막대그래프를 그려보자.
read_csv 메서드를 사용해 데이터를 불러오고 요일과 파티 숫자에 따라 교차 테이블 생성
tips = pd.read_csv('tips.csv')
tips
total_bill | tip | smoker | day | time | size | |
---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | No | Sun | Dinner | 4 |
... | ... | ... | ... | ... | ... | ... |
239 | 29.03 | 5.92 | No | Sat | Dinner | 3 |
240 | 27.18 | 2.00 | Yes | Sat | Dinner | 2 |
241 | 22.67 | 2.00 | Yes | Sat | Dinner | 2 |
242 | 17.82 | 1.75 | No | Sat | Dinner | 2 |
243 | 18.78 | 3.00 | No | Thur | Dinner | 2 |
244 rows × 6 columns
crosstab¶
party_counts = pd.crosstab(tips['day'], tips['size']) #교차분석표
party_counts
size | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
day | ||||||
Fri | 1 | 16 | 1 | 1 | 0 | 0 |
Sat | 2 | 53 | 18 | 13 | 1 | 0 |
Sun | 0 | 39 | 15 | 18 | 3 | 1 |
Thur | 1 | 48 | 4 | 5 | 1 | 3 |
#1인 6인 파티는 제외
party_counts = party_counts.loc[:, 2:5]
party_counts
size | 2 | 3 | 4 | 5 |
---|---|---|---|---|
day | ||||
Fri | 16 | 1 | 1 | 0 |
Sat | 53 | 18 | 13 | 1 |
Sun | 39 | 15 | 18 | 3 |
Thur | 48 | 4 | 5 | 1 |
그리고 각 로우의 합이 1이 되도록 정규화하고 그래프를 그려보자
party_counts.sum(1) #sum(1)은 열끼리 더하는 걸 뜻함
day Fri 18 Sat 85 Sun 75 Thur 58 dtype: int64
# 합이 1이 되도록 정규화
party_pcts = party_counts.div(party_counts.sum(1), axis=0)
party_pcts
size | 2 | 3 | 4 | 5 |
---|---|---|---|---|
day | ||||
Fri | 0.888889 | 0.055556 | 0.055556 | 0.000000 |
Sat | 0.623529 | 0.211765 | 0.152941 | 0.011765 |
Sun | 0.520000 | 0.200000 | 0.240000 | 0.040000 |
Thur | 0.827586 | 0.068966 | 0.086207 | 0.017241 |
party_pcts.plot.bar()
<Axes: xlabel='day'>
그래프를 그리기전 요약해야 하는 데이터는 seaborn 패키지를 이용하면 훨씬 간단하게 처리 가능
이번에는 seaborn 패키지로 팁 데이터를 다시 그려보자
seaborn¶
import seaborn as sns
tips['tip_pct'] = tips['tip']/ tips['total_bill'] - tips['tip']
tips.head()
total_bill | tip | smoker | day | time | size | tip_pct | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | No | Sun | Dinner | 2 | -0.950553 |
1 | 10.34 | 1.66 | No | Sun | Dinner | 3 | -1.499458 |
2 | 21.01 | 3.50 | No | Sun | Dinner | 3 | -3.333413 |
3 | 23.68 | 3.31 | No | Sun | Dinner | 2 | -3.170220 |
4 | 24.59 | 3.61 | No | Sun | Dinner | 4 | -3.463192 |
sns.barplot(x='tip_pct', y = 'day', data=tips, orient='h')
<Axes: xlabel='tip_pct', ylabel='day'>
seaborn 플로팅 함수의 data 인자는 pandas의 DataFrame을 받는다
다른 인자들은 컬럼 이름 참조
day 컬럼의 각 값에 대한 데이터는 여럿 존재하므로 tip_pct의 평균값으로 막대그래프를 그림
막대그래프 위에 덧그려진 검은 선은 95%의 신뢰구간을 나타냄(이 값은 옵션으로 설정 가능)
seaborn.barplot 메서드의 hue 옵션을 이용하면 추가 분류에 따라 나눠 그릴 수 있음
sns.barplot(x='tip_pct', y='day', hue='time', data=tips, orient='h')
<Axes: xlabel='tip_pct', ylabel='day'>
seaborn.set¶
seaborn 라이브러리는 자동으로 기본 색상 팔레트, 그래프 배경, 그리드 선 같은 꾸밈새 변경
seaborn.set 메서드를 이용해 이런 꾸밈새 변경 가능
sns.barplot(x='tip_pct', y='day', hue='time', data=tips, orient='h')
sns.set(style="whitegrid")
9.2.3 히스토그램과 밀도 그래프¶
히스토그램¶
히스토그램은 막대그래프의 한 종류로, 값들의 빈도를 분리해서 보여줌
데이터 포인트는 분리되어 고른 간격의 막대로 표현되며 데이터의 숫자가 막대의 높이로 표현됨
팁 데이터를 사용해 전체 결제금액 대비 팁 비율을 Series의 plot.hist 메서드를 사용해 만들어보자
tips['tip_pct'].plot.hist(bins=50)
<Axes: ylabel='Frequency'>
밀도 그래프¶
밀도 그래프는 관찰값을 사용해 추정되는 연속된 확률 분포를 그림
tips['tip_pct'].plot.density()
<Axes: ylabel='Density'>
sns.displot¶
seaborn 라이브러리의 displot을 이용해 히스토그램과 밀도 그래프를 한 번에 손쉽게 그리기 가능
예를 들어 두 개의 다른 표준정규분포로 이루어진 양봉분포(bimodal distribution)를 생각해보자
comp1 = np.random.normal(0,1, size=200)
comp1
array([-1.63433668e+00, 1.41007807e-01, -1.05736551e+00, -2.37950225e+00, -3.70766316e-01, -2.47960767e-02, 1.99336244e-01, -5.20330462e-02, -5.96031295e-01, 3.06100417e+00, 9.91404422e-01, -1.17655764e+00, 1.78098642e+00, -1.26412042e+00, 7.98922360e-01, 1.76563446e-01, 2.50866796e-01, -1.23570992e+00, -2.34544874e-02, -7.21689373e-04, -1.59032438e+00, -4.44708333e-01, 1.18992017e+00, 1.25281698e-01, 6.57602141e-01, 7.81725518e-01, -1.15458405e-01, 3.96528880e-02, -6.93569377e-01, 4.68395093e-01, -4.72115564e-01, -1.42060389e+00, 2.29215112e+00, 4.54536919e-01, -1.08936897e-01, 5.50385569e-01, 6.44014899e-01, -5.96606862e-02, 5.08657678e-01, 6.61864306e-01, -1.48707385e+00, -4.95248424e-02, -6.39054317e-01, 7.81116115e-01, -1.60205086e+00, 5.12215875e-01, 1.50368496e-01, 2.47050508e-01, -6.44916721e-01, 1.75433313e+00, 4.32359877e-01, 1.76377936e+00, -2.07420545e+00, 7.17390116e-01, 1.75205538e+00, 7.54427064e-01, -1.13647726e+00, 1.47736587e-01, -1.43339461e-01, -5.71005354e-01, 5.18493608e-01, 1.26474349e+00, 7.72118978e-01, -2.06879594e+00, -7.25594657e-02, -3.09594163e-02, 1.37271315e+00, -1.06814094e+00, 1.93066755e-01, 8.41914787e-01, -1.05669749e+00, 5.39489584e-01, -9.62204749e-01, -6.11759380e-01, 2.86773784e-01, 5.86432572e-01, -1.47029912e+00, -6.92988886e-01, 1.19742113e+00, -1.61818789e-01, -2.74419339e-02, -1.19643843e+00, 9.27477136e-01, 3.77005931e-01, 5.21249467e-01, 1.26091013e+00, 3.40537266e-01, 6.72164191e-01, 9.31529038e-01, 6.87836941e-01, -2.10190781e-01, 1.66673201e+00, -6.82442549e-01, -4.74597730e-01, 1.86768108e-01, -1.43812384e+00, 1.65678401e+00, 1.11639327e+00, -1.91565911e-01, -4.47350136e-01, 6.49524767e-01, 1.79977538e+00, 5.39665691e-01, 3.08005996e-03, 5.77893622e-01, -3.06417764e-02, 5.90963838e-01, -1.65496801e+00, -4.89369061e-01, -2.63687673e-02, 3.52287088e-01, -1.56830981e+00, 5.33757647e-01, 3.50520032e-01, -2.82583597e-01, 8.37435057e-01, 8.32597450e-01, -5.11542191e-01, -3.45603994e-01, -3.29506605e-01, -5.40968981e-01, 1.10104674e+00, -5.32055119e-02, -7.03286966e-01, -2.68795439e-01, -3.41126731e-01, -1.28400426e+00, 3.16443628e-01, -4.82064440e-01, 3.27388245e-01, 6.17888244e-01, 2.39489867e+00, -6.23150713e-01, 1.32405764e+00, 2.40314062e+00, -6.99778157e-01, 6.38837108e-01, 2.05990672e-01, 2.79260030e-01, 7.93389358e-01, -1.19431957e+00, -2.86221330e-01, -2.38345312e+00, -5.09823936e-02, -5.02546924e-01, -1.39322235e+00, 2.96838237e+00, 2.34164996e-01, 1.74699904e+00, -9.65333024e-01, 1.01231239e+00, -2.32375696e+00, 6.26596059e-02, -4.11356009e-01, 3.75106960e-01, -6.03956507e-01, -6.61975005e-01, 2.82201647e-01, 7.49425649e-01, 7.43216729e-01, 2.02012867e+00, 5.74164538e-01, 5.11549105e-02, -3.21009795e-02, -1.14430797e-01, -1.95996287e-01, -7.59609534e-01, -5.51311293e-01, 1.40692950e-01, -5.95205543e-01, 6.48161897e-01, 1.29053982e+00, -1.00275867e-01, -2.68275283e-01, 7.67924919e-01, 9.81434552e-01, 8.22580173e-01, 2.50746697e-01, 7.69601289e-01, 3.45856038e-01, 2.06194809e-01, 1.66646735e+00, -7.08370117e-02, 1.05214283e+00, -1.02205176e+00, 9.72740623e-01, -7.99934628e-01, 5.85073699e-01, 2.01407003e-01, 2.86187785e-01, 6.43623304e-01, -8.79236298e-02, -5.06918064e-01, 2.07918287e+00, 1.03346122e+00, 1.95847611e+00, -2.81867171e-01, -1.48532518e-01, 9.98859392e-01, -1.48479801e-01])
comp2 = np.random.normal(10,2,size=200)
comp2
array([10.46079755, 8.49847732, 11.33010525, 11.2807846 , 8.48953138, 10.29199557, 8.75641328, 10.54339891, 13.90211832, 10.73448251, 9.16767578, 6.22379314, 10.2273564 , 10.75439501, 9.53785888, 12.00763306, 10.65386578, 10.9603497 , 10.23434935, 9.75156721, 14.9913288 , 8.36332521, 8.1835365 , 11.56559391, 10.61230399, 13.46995669, 10.2366222 , 9.93136135, 11.18431834, 8.53781434, 8.88439953, 9.21009063, 11.54577612, 15.49998036, 7.57441496, 9.65616865, 7.1922367 , 12.3287178 , 9.73278243, 8.58335183, 10.78755004, 6.84442271, 6.21534669, 6.44011484, 10.86245993, 10.88326327, 10.30901432, 8.65791551, 10.16560136, 12.00409999, 11.20426883, 10.07455232, 7.91935486, 10.83308535, 7.72382927, 12.98914673, 13.35134796, 8.32024479, 10.48535117, 10.1471672 , 16.68414094, 10.07906014, 11.46337605, 10.24880275, 10.28144346, 6.15514136, 9.3619584 , 11.77868036, 6.46371672, 11.92614241, 9.56325529, 8.15469442, 8.58436492, 11.15040753, 13.48698367, 10.23852887, 10.88116003, 10.87523284, 11.05613584, 11.41211066, 10.44557608, 10.19488447, 10.75449285, 10.59732289, 10.38123936, 12.59045918, 11.51293461, 7.57806792, 11.84226676, 9.58291643, 11.28290026, 8.84228278, 10.03439413, 12.03672898, 6.94187549, 9.08462198, 10.87121693, 6.71467688, 8.98854319, 13.65127223, 12.86858779, 8.1671013 , 11.63011853, 10.99384455, 9.77603824, 7.97510347, 11.27393031, 11.67006766, 11.55250083, 8.69101376, 9.30737221, 9.47539404, 11.70948437, 10.41270073, 10.10259179, 9.55675431, 10.16707075, 11.61976131, 10.13444432, 11.60339678, 11.17566735, 8.90090298, 8.88298143, 9.5877812 , 6.34552567, 7.09757612, 8.75716764, 11.33830439, 10.14172647, 9.94123439, 13.52574481, 12.780414 , 7.06406538, 9.80523991, 8.43726323, 15.58346866, 6.35748257, 10.55941936, 12.78693262, 10.25951086, 9.0498645 , 10.96037407, 8.84529867, 9.91385792, 12.78847853, 12.71545064, 9.57616024, 9.41712082, 11.38450382, 7.06631324, 6.73480848, 7.95729708, 9.42342199, 9.26032133, 9.49795403, 10.60168143, 9.76551291, 7.83935573, 10.40614716, 11.29144812, 8.70049781, 7.41503937, 11.32718662, 12.72620069, 6.8389343 , 11.56140502, 8.68773885, 10.44709739, 8.45164827, 8.31972147, 9.05883384, 9.24444633, 9.97705312, 10.62493858, 10.38632689, 7.36531638, 11.35688769, 7.19225548, 12.28164449, 6.9807975 , 9.49064577, 8.95353796, 9.86590976, 9.90951995, 9.25029677, 7.35772809, 13.71983828, 10.6547178 , 10.44816113, 9.96525774, 10.55438045, 11.93727179, 7.95096326, 11.38998316, 12.77768982, 12.23365018, 13.26777947, 4.54341868, 11.77772323, 8.4879443 ])
values = pd.Series(np.concatenate([comp1, comp2]))
values
0 -1.634337 1 0.141008 2 -1.057366 3 -2.379502 4 -0.370766 ... 395 12.233650 396 13.267779 397 4.543419 398 11.777723 399 8.487944 Length: 400, dtype: float64
sns.distplot(values, bins=100, color='k')
C:\Users\ADMIN\AppData\Local\Temp\ipykernel_17592\3498537128.py:1: UserWarning: `distplot` is a deprecated function and will be removed in seaborn v0.14.0. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms). For a guide to updating your code to use the new functions, please see https://gist.github.com/mwaskom/de44147ed2974457ad6372750bbe5751 sns.distplot(values, bins=100, color='k')
<Axes: ylabel='Density'>
9.2.4 산포도¶
산포도(scatter plot, point plot)은 두 개의 1차원 데이터 묶음 간의 관계를 나타내고자 할 때 유용한 그래프
statsmodel 프로젝트에서 macrodata 데이터 묶음을 불러온 다음 몇 가지 변수를 선택하고 로그차를 구해보자
macro = pd.read_csv('macrodata.csv')
macro
year | quarter | realgdp | realcons | realinv | realgovt | realdpi | cpi | m1 | tbilrate | unemp | pop | infl | realint | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1959 | 1 | 2710.349 | 1707.4 | 286.898 | 470.045 | 1886.9 | 28.980 | 139.7 | 2.82 | 5.8 | 177.146 | 0.00 | 0.00 |
1 | 1959 | 2 | 2778.801 | 1733.7 | 310.859 | 481.301 | 1919.7 | 29.150 | 141.7 | 3.08 | 5.1 | 177.830 | 2.34 | 0.74 |
2 | 1959 | 3 | 2775.488 | 1751.8 | 289.226 | 491.260 | 1916.4 | 29.350 | 140.5 | 3.82 | 5.3 | 178.657 | 2.74 | 1.09 |
3 | 1959 | 4 | 2785.204 | 1753.7 | 299.356 | 484.052 | 1931.3 | 29.370 | 140.0 | 4.33 | 5.6 | 179.386 | 0.27 | 4.06 |
4 | 1960 | 1 | 2847.699 | 1770.5 | 331.722 | 462.199 | 1955.5 | 29.540 | 139.6 | 3.50 | 5.2 | 180.007 | 2.31 | 1.19 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
198 | 2008 | 3 | 13324.600 | 9267.7 | 1990.693 | 991.551 | 9838.3 | 216.889 | 1474.7 | 1.17 | 6.0 | 305.270 | -3.16 | 4.33 |
199 | 2008 | 4 | 13141.920 | 9195.3 | 1857.661 | 1007.273 | 9920.4 | 212.174 | 1576.5 | 0.12 | 6.9 | 305.952 | -8.79 | 8.91 |
200 | 2009 | 1 | 12925.410 | 9209.2 | 1558.494 | 996.287 | 9926.4 | 212.671 | 1592.8 | 0.22 | 8.1 | 306.547 | 0.94 | -0.71 |
201 | 2009 | 2 | 12901.504 | 9189.0 | 1456.678 | 1023.528 | 10077.5 | 214.469 | 1653.6 | 0.18 | 9.2 | 307.226 | 3.37 | -3.19 |
202 | 2009 | 3 | 12990.341 | 9256.0 | 1486.398 | 1044.088 | 10040.6 | 216.385 | 1673.9 | 0.12 | 9.6 | 308.013 | 3.56 | -3.44 |
203 rows × 14 columns
data = macro[['cpi', 'm1', 'tbilrate', 'unemp']]
data
cpi | m1 | tbilrate | unemp | |
---|---|---|---|---|
0 | 28.980 | 139.7 | 2.82 | 5.8 |
1 | 29.150 | 141.7 | 3.08 | 5.1 |
2 | 29.350 | 140.5 | 3.82 | 5.3 |
3 | 29.370 | 140.0 | 4.33 | 5.6 |
4 | 29.540 | 139.6 | 3.50 | 5.2 |
... | ... | ... | ... | ... |
198 | 216.889 | 1474.7 | 1.17 | 6.0 |
199 | 212.174 | 1576.5 | 0.12 | 6.9 |
200 | 212.671 | 1592.8 | 0.22 | 8.1 |
201 | 214.469 | 1653.6 | 0.18 | 9.2 |
202 | 216.385 | 1673.9 | 0.12 | 9.6 |
203 rows × 4 columns
trans_data = np.log(data).diff().dropna()
trans_data[-5:]
cpi | m1 | tbilrate | unemp | |
---|---|---|---|---|
198 | -0.007904 | 0.045361 | -0.396881 | 0.105361 |
199 | -0.021979 | 0.066753 | -2.277267 | 0.139762 |
200 | 0.002340 | 0.010286 | 0.606136 | 0.160343 |
201 | 0.008419 | 0.037461 | -0.200671 | 0.127339 |
202 | 0.008894 | 0.012202 | -0.405465 | 0.042560 |
sns.regplot¶
seaborn 라이브러리의 regplot 메서드를 이용해 산포도와 선형회귀곡선을 함께 그릴 수 있음
sns.regplot(x = 'm1', y= 'unemp', data=trans_data)
<Axes: xlabel='m1', ylabel='unemp'>
sns.regplot(x = 'm1', y= 'unemp', data=trans_data)
plt.title('Changes in log %s versus log %s' % ('m1', 'unemp'))
Text(0.5, 1.0, 'Changes in log m1 versus log unemp')
sns.pairplot¶
seaborn에서는 pairplot 함수를 제공해 대각선을 따라 각 변수에 대한 히스토그램이나 밀도 그래프 생성 가능
sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha':0.2})
<seaborn.axisgrid.PairGrid at 0x2142fe066b0>
plot_kws¶
plot_kws 인자는 각각의 그래프에 전달한 개별 설정값 지정
'Python, Jupyter 🐍 > [python]파이썬 데이터분석' 카테고리의 다른 글
11장 (0) | 2023.04.19 |
---|---|
지도에 서울소재대학 위치 표시하기 (0) | 2023.04.18 |
10장 데이터 집계와 그룹 연산 (0) | 2023.04.17 |
7장 (0) | 2023.04.17 |
[오류] 'jupyter'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는배치 파일이 아닙니다. (0) | 2023.04.09 |