Seaborn을 이용해 데이터 시각화하기
Seaborn을 이용해서 데이터 시각화하기¶
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
tips 데이터 분석 : boxplot()
,
swarmplot()
, lmplot()
¶
tips = sns.load_dataset('tips')
tips
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
... | ... | ... | ... | ... | ... | ... | ... |
239 | 29.03 | 5.92 | Male | No | Sat | Dinner | 3 |
240 | 27.18 | 2.00 | Female | Yes | Sat | Dinner | 2 |
241 | 22.67 | 2.00 | Male | Yes | Sat | Dinner | 2 |
242 | 17.82 | 1.75 | Male | No | Sat | Dinner | 2 |
243 | 18.78 | 3.00 | Female | No | Thur | Dinner | 2 |
244 rows × 7 columns
당신은 알바 컨설턴트입니다. 알바를 구하러 온 사람이 가장 높은 팁을 받을 수 있도록 도와주어야 합니다.
# 이 분은 어느 요일에 일을 해야 할까요?
tips.groupby(['day'], observed=False)[['tip']].aggregate(['mean', 'count', 'sum']).reset_index()
day | tip | |||
---|---|---|---|---|
mean | count | sum | ||
0 | Thur | 2.771452 | 62 | 171.83 |
1 | Fri | 2.734737 | 19 | 51.96 |
2 | Sat | 2.993103 | 87 | 260.40 |
3 | Sun | 3.255132 | 76 | 247.39 |
groupby()
와 aggregate()
를 이용해서 각
요일 별 평균, 횟수(팁을 받은 수), 총 받은 팁을 구해보았습니다.
토요일이 합계는 가장 크긴 하지만 손님 수(87)도 가장 많으므로 힘들 것 같습니다. 게다가 평균을 확인해보면 토요일은 약 3 정도로, 3.2인 일요일보다 평균적으로 더 적은 팁을 받는 것을 알 수 있습니다. 알바를 구하러 온 사람에게 추천하기 가장 적절한 요일은 일요일로 보입니다.
# 저녁과 낮 중 언제 일해야 할까요?
tips.groupby(['day', 'time'], observed=False)[['tip']].aggregate(['sum', 'count'])
tip | |||
---|---|---|---|
sum | count | ||
day | time | ||
Thur | Lunch | 168.83 | 61 |
Dinner | 3.00 | 1 | |
Fri | Lunch | 16.68 | 7 |
Dinner | 35.28 | 12 | |
Sat | Lunch | 0.00 | 0 |
Dinner | 260.40 | 87 | |
Sun | Lunch | 0.00 | 0 |
Dinner | 247.39 | 76 |
주말 점심에 sum과 count 값이 0인 것으로 보아, 주말에는 저녁 장사만 하는 것 같습니다. 목요일과 금요일은 팁이 주말에 비해 상대적으로 적습니다. 조금 고생하더라도 많은 돈을 팁을 받고 싶다면 주말에 일하는 게 좋아 보입니다.
그럼, boxplot()
을 이용해서 상자수염그림을
살펴보겠습니다.
sns.boxplot(data=tips, x='day', y='tip', hue='time')
<Axes: xlabel='day', ylabel='tip'>
토요일에 사람들이 평소보다 많은 팁을 주는 경우가 많았습니다.
# 어떤 손님에게 서빙해야 팁을 많이 받을 수 있을까요?
tips.groupby(['sex', 'smoker'], observed=False)[['tip']].aggregate(['sum', 'mean', 'count'])
tip | ||||
---|---|---|---|---|
sum | mean | count | ||
sex | smoker | |||
Male | Yes | 183.07 | 3.051167 | 60 |
No | 302.00 | 3.113402 | 97 | |
Female | Yes | 96.74 | 2.931515 | 33 |
No | 149.77 | 2.773519 | 54 |
어떤 손님에게 서빙해야 팁을 더 많이 받을 수 있는지 살펴보기 위해 손님의 유형을 성별과 흡연 여부로 나눠보았습니다. 비흡연자 남성이 팁을 주는 경우가 가장 많았고, 평균도 가장 높습니다. 비흡연자 남성에게 서빙하는 것이 가장 많은 팁을 받을 수 있는 방법이라고 할 수 있겠습니다.
# sns.boxplot(data=tips, x='day', y='tip', hue='sex')
sns.boxplot(data=tips, x='day', y='tip')
sns.swarmplot(data=tips, x='day', y='tip')
<Axes: xlabel='day', ylabel='tip'>
boxplot()
을 이용해 상자수염 그림을 그리면 이상치는
쉽게 파악할 수 있지만 값의 분포를 살펴보기 쉽지 않습니다. 이런
경우에는 swarmplot()
을 이용하면 데이터 포인트를
겹치지 않게 표시하여 데이터의 분포를 직관적으로 확인할 수
있습니다.
결론¶
- 토요일과 일요일이 고민이 된다. 상황마다 다를 것이다.
- 팁 자체를 많이 받고자 하면 일요일이 가장 많은 팁을 받았다.
- 하지만 노동 강도를 줄이면서 높은 팁을 받고자 한다면 토요일도 좋은 선택이 될 것이다.
- 목, 금은 점심, 저녁 장사를 하고 있지만 주말에는 저녁 장사만 한다.
가설 설정하기¶
데이터를 분석하기에 앞서, 가설을 설정하고 해당 가설이 맞는지를 분석과 시각화를 통해 알아볼 수도 있습니다.
'total_bill이 높을수록 tip도 높을 것이다.' 라는
가설을 세우고 이것을 검증해보겠습니다. pandas의
corr()
함수를 사용하면 상관분석을 할 수 있습니다.
tips.corr(numeric_only=True)
total_bill | tip | size | |
---|---|---|---|
total_bill | 1.000000 | 0.675734 | 0.598315 |
tip | 0.675734 | 1.000000 | 0.489299 |
size | 0.598315 | 0.489299 | 1.000000 |
이것을 시각화하기 위해 seaborn의 lmplot()
을
사용합니다. lmplot
을 사용하면 산점도와 회귀선을
함께 그려서 데이터의 관계를 시각적으로 확인할 수 있습니다.
sns.lmplot(data=tips, x='total_bill', y='tip')
<seaborn.axisgrid.FacetGrid at 0x165a14dd0>
회귀선 원리¶
x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 6, 8, 10])
m, b = np.polyfit(x, y, 1)
m, b
(np.float64(2.0), np.float64(-2.3832327871173813e-15))
x = tips['total_bill'] # 독립변수
y = tips['tip'] # 종속변수
m, b = np.polyfit(x, y, 1)
plt.scatter(x, y)
plt.plot(x, m * x + b)
print(f'회귀선 y = {m:.3f}x + {b:.3f}')
# 기울기가 0.11 => total_bill이 1 증가할 때 tip이 0.1 증가한다.
# total_bill이 10달러 증가할 때 tipdl 1.05달러 증하한다.
회귀선 y = 0.105x + 0.920
시계열 데이터 (flight dataset) : pivot()
,
heatmap()
¶
시계열 데이터는 시간에 따라 측정된 데이터 포인트의 순서를 나타내는 데이터입니다. Seaborn에서 제공하는 flisghts 데이터셋을 사용해서 확인해보겠습니다.
데이터는 연도, 월, 탑승객 수로 이루어진 간단한 데이터입니다.
flights = sns.load_dataset('flights')
flights.head(3)
year | month | passengers | |
---|---|---|---|
0 | 1949 | Jan | 112 |
1 | 1949 | Feb | 118 |
2 | 1949 | Mar | 132 |
pivot()
과 heatmap()
¶
pivot()
을 이용해서 월을 행, 연도를 열로 하는 피봇
차트를 만들고 이를 heatmap()
으로 표현해보겠습니다.
heatmap()
에서 annot
을 True로 설정하면
데이터의 값을 히트맵 상에 노출합니다.
# 연도별 month
flights_pivot = flights.pivot(index='month', columns='year')
sns.heatmap(data=flights_pivot, annot=True, fmt='d')
<Axes: xlabel='None-year', ylabel='month'>
flights_pivot
passengers | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
year | 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1955 | 1956 | 1957 | 1958 | 1959 | 1960 |
month | ||||||||||||
Jan | 112 | 115 | 145 | 171 | 196 | 204 | 242 | 284 | 315 | 340 | 360 | 417 |
Feb | 118 | 126 | 150 | 180 | 196 | 188 | 233 | 277 | 301 | 318 | 342 | 391 |
Mar | 132 | 141 | 178 | 193 | 236 | 235 | 267 | 317 | 356 | 362 | 406 | 419 |
Apr | 129 | 135 | 163 | 181 | 235 | 227 | 269 | 313 | 348 | 348 | 396 | 461 |
May | 121 | 125 | 172 | 183 | 229 | 234 | 270 | 318 | 355 | 363 | 420 | 472 |
Jun | 135 | 149 | 178 | 218 | 243 | 264 | 315 | 374 | 422 | 435 | 472 | 535 |
Jul | 148 | 170 | 199 | 230 | 264 | 302 | 364 | 413 | 465 | 491 | 548 | 622 |
Aug | 148 | 170 | 199 | 242 | 272 | 293 | 347 | 405 | 467 | 505 | 559 | 606 |
Sep | 136 | 158 | 184 | 209 | 237 | 259 | 312 | 355 | 404 | 404 | 463 | 508 |
Oct | 119 | 133 | 162 | 191 | 211 | 229 | 274 | 306 | 347 | 359 | 407 | 461 |
Nov | 104 | 114 | 146 | 172 | 180 | 203 | 237 | 271 | 305 | 310 | 362 | 390 |
Dec | 118 | 140 | 166 | 194 | 201 | 229 | 278 | 306 | 336 | 337 | 405 | 432 |