25 분 소요

4강. 데이터 정제와 그래프 시각화

  • 둘째마당 (07-08장)

  • pp.177-221

# 그래프 해상도 설정
import matplotlib.pyplot as plt
plt.rcParams.update({'figure.dpi' : '100'})
%config InlineBackend.figure_format = 'retina'

07. 데이터 정제 - 빠진 데이터, 이상한 데이터 제거하기

07-1. 빠진 데이터를 찾아라! - 결측치 정제하기 (178-185쪽)

[Do it! 실습] 결측치 찾기(178쪽)

  • 결측치 : 누락된 값, 비어 있는 값

  • 결측치 있는 경우 : 함수가 적용되지 않거나, 분석 결과가 왜곡되는 문제 발생

  • 실제 데이터 분석시, 결측치 여부 확인해서 제거하는 정제 과정을 거친 다음에 분석해야 함

결측치 만들기

  • Numpy 패키지의 np.nan을 입력 -> NaN으로 표시
import pandas as pd
import numpy as np

df = pd.DataFrame({'sex'   : ['M', 'F', np.nan, 'M', 'F'],
                   'score' : [5, 4, 3, 4, np.nan]})
df
sex score
0 M 5.0
1 F 4.0
2 NaN 3.0
3 M 4.0
4 F NaN
# NaN이 있는 상태로 연산하면 출력 결과도 NaN이 된다

df['score'] + 1
0    6.0
1    5.0
2    4.0
3    5.0
4    NaN
Name: score, dtype: float64

결측치 확인하기

  • pd.isna()를 이용하면 결측치 포함 여부를 알 수 있다.

  • pd.isna().sum()으로 결측치 총 개수를 알 수 있다.

# df의 결측치 포함 여부 파악
pd.isna(df)
sex score
0 False False
1 False False
2 False False
3 True False
4 False False
5 False True
# df의 결측치 총 개수 파악
pd.isna(df).sum()
sex      1
score    1
dtype: int64

[Do it! 실습] 결측치 제거하기(180쪽)

  • df.dropna() 이용하면 결측치가 있는 “행”을 제거할 수 있다.

  • 이 때 결측치의 위치는 subset에 []를 이용해서 변수명을 입력하면 된다.

  • subset: ‘부분집합’이라는 의미

결측치 있는 행 제거하기

# score의 결측치 제거해서 df_nomiss에 저장하라
df_nomiss = df.dropna(subset = ['score'])
df_nomiss
sex score
0 M 5.0
1 F 4.0
2 NaN 3.0
3 M 4.0

여러 번수에 결측치 없는 데이터 추출하기

  • df.dropna()의 subset에 변수를 나열하면, 여러 변수에 결측치가 없는 행을 추출할 수 있다.
# score와 sex의 두 변수에 있는 결측치를 제거해서 변수 df_nomiss에 저장하라
df_nomiss = df.dropna(subset = ['score', 'sex'])
df_nomiss
sex score
0 M 5.0
1 F 4.0
3 M 4.0

결측치가 하나라도 있으면 제거하기

  • df.dropna()에 아무 변수도 지정하지 않으면 모든 변수에 결측치가 없는 행만 남긴다.

  • 단, 이 경우 분석에 필요한 행까지 손실되는 단점이 있음 -> 변수를 직접 지정해 결측치 제거하는 것을 권장 (-> 181~182쪽 설명)

df_nomiss2 = df.dropna()
df_nomiss2
sex score
0 M 5.0
1 F 4.0
3 M 4.0

[Do it! 실습] 결측치 대체하기(182쪽)

  • 데이터가 작고 결측치가 많을 때, 결측치를 제거하면 너무 많은 데이터가 손실되어 분석 결과가 왜곡되는 문제 발생

  • 이 때, 결측치를 제거하는 대신, 다른 값으로 채워 넣기도 함 = 결측치 대체법

  • 대표값(평균값이나 최빈값 등)으로 대체하거나, 통계 분석 기법으로 결측치의 예측값을 추정해 대체함

평균값으로 결측치 대체하기

# exam.csv 파일을 불러와 일부 값을 결측지로 바꿈
exam = pd.read_csv('exam.csv')           # 데이터 불러오기
exam.loc[[2, 7, 14], ['math']] = np.nan  # 2, 7, 14행의 math에 NaN 할당  
                                         # df.loc[]는 데이터 위치 지정하는 역할 [ , ]에서 쉼표 왼쪽은 행 위치, 오른쪽은 열 위치를 의미
exam
id nclass math english science
0 1 1 50.0 98 50
1 2 1 60.0 97 60
2 3 1 NaN 86 78
3 4 1 30.0 98 58
4 5 2 25.0 80 65
5 6 2 50.0 89 98
6 7 2 80.0 90 45
7 8 2 NaN 78 25
8 9 3 20.0 98 15
9 10 3 50.0 98 45
10 11 3 65.0 65 65
11 12 3 45.0 85 32
12 13 4 46.0 98 65
13 14 4 48.0 87 12
14 15 4 NaN 56 78
15 16 4 58.0 98 65
16 17 5 65.0 68 98
17 18 5 80.0 78 90
18 19 5 89.0 68 87
19 20 5 78.0 83 58
# math의 평균값 : mean()의 경우 자동으로 결측치 제외하고 평균 구함 (182쪽 참조)
# math의 평균값을 구하라
exam['math'].mean()
55.2
# 결측치를 평균값으로 정한 55로 대체하라
exam['math'] = exam['math'].fillna(55)
exam
id nclass math english science
0 1 1 50.0 98 50
1 2 1 60.0 97 60
2 3 1 55.0 86 78
3 4 1 30.0 98 58
4 5 2 25.0 80 65
5 6 2 50.0 89 98
6 7 2 80.0 90 45
7 8 2 55.0 78 25
8 9 3 20.0 98 15
9 10 3 50.0 98 45
10 11 3 65.0 65 65
11 12 3 45.0 85 32
12 13 4 46.0 98 65
13 14 4 48.0 87 12
14 15 4 55.0 56 78
15 16 4 58.0 98 65
16 17 5 65.0 68 98
17 18 5 80.0 78 90
18 19 5 89.0 68 87
19 20 5 78.0 83 58

[개인 실습] 혼자서 해보기(185쪽)

  • 결측치가 들어 있는 mpg 데이터를 이용해 분석 문제를 해결해 보세요
# 일부러 몇 개의 결측치를 입력하기

# mpg 데이터 불러오기
mpg = pd.read_csv('mpg.csv')

# NaN 할당하기
mpg.loc[[64, 123, 130, 152, 211], 'hwy'] = np.nan

mpg
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18 29.0 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21 29.0 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20 31.0 p compact
3 audi a4 2.0 2008 4 auto(av) f 21 30.0 p compact
4 audi a4 2.8 1999 6 auto(l5) f 16 26.0 p compact
... ... ... ... ... ... ... ... ... ... ... ...
229 volkswagen passat 2.0 2008 4 auto(s6) f 19 28.0 p midsize
230 volkswagen passat 2.0 2008 4 manual(m6) f 21 29.0 p midsize
231 volkswagen passat 2.8 1999 6 auto(l5) f 16 26.0 p midsize
232 volkswagen passat 2.8 1999 6 manual(m5) f 18 26.0 p midsize
233 volkswagen passat 3.6 2008 6 auto(s6) f 17 26.0 p midsize

234 rows × 11 columns

Q1. drv(구동 방식)별로 hwy(고속도로 연비) 평균이 어떻게 다른지 알아보려 합니다. 분석 전에 우선 두 변수에 결측치가 있는지 확인해야 합니다. drv 변수와 hwy 변수에 결측치가 몇 개 있는지 알아보세요

  • 힌트 : 결측치 확인하는 df.isna()와 합계를 구하는 sum()를 조합해 보세요
mpg.head()
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18 29.0 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21 29.0 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20 31.0 p compact
3 audi a4 2.0 2008 4 auto(av) f 21 30.0 p compact
4 audi a4 2.8 1999 6 auto(l5) f 16 26.0 p compact
# drv 변수와 hwy 변수에 있는 결측치 개수를 확인하라
mpg[['drv', 'hwy']].isna().sum()
drv    0
hwy    5
dtype: int64

Q2. df.dropna()를 이용해 hwy변수의 결측치를 제거하고, 어떤 구동방식의 hwy 평균이 높은지 알아보세요. 하나의 pandas 구문으로 만들어야 합니다.

mpg.dropna(subset = ['hwy']) \
   .groupby('drv') \
   .agg(mean_hwy = ('hwy', 'mean'))
mean_hwy
drv
4 19.242424
f 28.200000
r 21.000000

07-2. 이상한 데이터를 찾아라! - 이상치 정제하기 (186-195쪽)

  • 이상치 : 정상 범위에서 크게 벗어난 값

  • 이상치가 들어 있으면 분석 결과가 왜곡되므로 분석에 앞서 이상치를 제거하는 작업을 해야 함

[Do it! 실습] 이상치 제거하기 - 존재할 수 없는 값(186쪽)

  • 논리적으로 존재할 수 없는 값이 들어 있을 때가 있다.

    • 예 : 남자는 1, 여자는 2로 되어 있는 성별 변수에 3이라는 값이 들어있는 경우
# 이상치 들어 있는 데이터 생성 (1, 2로 분류되는 'sex' 변수, 1~5점으로 된 score 변수)

df = pd.DataFrame({'sex'   : [1, 2, 1, 3, 2, 1],
                   'score' : [5, 4, 3, 4, 2, 6]})
df
sex score
0 1 5
1 2 4
2 1 3
3 3 4
4 2 2
5 1 6

이상치 확인하기

  • df.value_counts() 이용해 빈도표를 만들면 됨
# df 중 sex 변수에 들어 있는 값의 빈도표 만들기
df['sex'].value_counts().sort_index()
# df.value_counts()에 sort_index()를 적용하면 빈도 기준으로 내림차순 정렬하지 않고, 변수의 값 순서로 정렬
sex
1    3
2    2
3    1
Name: count, dtype: int64
# df 중 score 변수에 들어 있는 값의 빈도표 만들기
df['score'].value_counts().sort_index()
score
2.0    1
3.0    1
4.0    2
5.0    1
Name: count, dtype: int64

결측 처리하기

  • 확인한 이상치를 결측치로 변환

  • np.where()를 이용해 이상치에 NaN을 부여

# sex가 3이면 NaN 부여
df['sex'] = np.where(df['sex'] == 3, np.nan, df['sex'])
df
sex score
0 1.0 5.0
1 2.0 4.0
2 1.0 3.0
3 NaN 4.0
4 2.0 2.0
5 1.0 NaN
# score가 5보다 크면 NaN 부여
df['score'] = np.where(df['score'] > 5, np.nan, df['score'])
df
sex score
0 1.0 5.0
1 2.0 4.0
2 1.0 3.0
3 NaN 4.0
4 2.0 2.0
5 1.0 NaN
# df.dropna() 이용해 결측치 제거한 다음 성별에 따른 score 평균을 구한다.

df.dropna(subset = ['sex', 'score']) \
  .groupby('sex') \
  .agg(score_mean = ('score', 'mean'))
score_mean
sex
1.0 4.0
2.0 3.0
# np.where()는 반환 값 중 문자가 있으면, np.nan을 지정해도 결측치 NaN이 아니라 문자 'nan'을 반환
# 이 경우엔 먼저 np.where() 이용해 결측치로 만들 값에 특정 문자(예: 'etc')를 부여 -> df.replace() 이용해 그 문자를 np.nan으로 변환
# (189쪽 참조)

[Do it! 실습] 이상치 제거하기 - 극단적인 값(190쪽)

  • 논리적으로 존재할 수 있지만 극단적으로 크거나 작은 값 = 극단치

    • 예 : 몸무게 변수에 200kg 이상의 값이 있는 경우
  • 극단치 제거 위해서는 먼저 어디까지를 정상 범위로 볼 것인가를 정해야 함

    • 논리적 판단에 의한 방법 : 성인 몸무게의 정상 범위를 40~150kg로 설정

    • 통계적 기준 이용 : 상하위 0.3% 또는 +-3 표준편차에 해당하는 값을 극단치로 간주

  • 상자 그림으로 극단치 기준 정하기

    • 상자 그림 : 데이터의 분포를 직사각형의 상자 모양으로 표현한 그래프 -> 데이터의 분포를 한눈에 알 수 있음

상자 그림 살펴보기

  • mpg 데이터의 hwy 변수로 상자 그림 작성. seaborn 패키지의 boxplot() 이용
import pandas as pd
mpg = pd.read_csv('mpg.csv')

import seaborn as sns
sns.boxplot(data = mpg, y = 'hwy')
<Axes: ylabel='hwy'>

  • 상자 그림 : 값을 크기 순으로 나열해 4등분 했을 때 위치하는 값인 ‘사분위수’를 이용해 만듦

  • 상자 그림의 요소가 나타내는 값 -> 교재 191쪽

극단치 기준값 구하기

# 1사분위수, 3사분위수 구하기 : df.quantile() 이용, 변수는 각각 pct25, pct75
pct25 = mpg['hwy'].quantile(.25) # 하위 25%에 해당하는 1사분위수
pct25
18.0
pct75 = mpg['hwy'].quantile(.75) # 하위 75%에 해당하는 3사분위수
pct75
27.0
# IQR 구하기 : IQR(inter quartile range, 사분위 범위) <- 1사분위수와 3사분위수 간의 거리
iqr = pct75 - pct25
iqr
9.0
# 하한, 상한 구하기 : 극단치의 경계값 (하한 - 1사분위수보다 'IQR의 1.5배'만큼 더 작은 값, 상한 - 3사분위수보다 더 큰 값)
pct25 - 1.5 * iqr # 하한
4.5
pct75 + 1.5 * iqr # 상한
40.5
# 극단치를 결측 처리하기 : np.where() 이용하라. 
# 여러 조건 입력시 각 조건을 괄호로 감싸도록 주의
import numpy as np
mpg['hwy'] = np.where((mpg['hwy'] < 4.5) | (mpg['hwy'] > 40.5), 
                      np.nan, mpg['hwy'])
# 결측치 빈도 확인
mpg['hwy'].isna().sum()
3
# 해당 값 확인
mpg[mpg['hwy'].isna()]
manufacturer model displ year cyl trans drv cty hwy fl category
212 volkswagen jetta 1.9 1999 4 manual(m5) f 33 NaN d compact
221 volkswagen new beetle 1.9 1999 4 manual(m5) f 35 NaN d subcompact
222 volkswagen new beetle 1.9 1999 4 auto(l4) f 29 NaN d subcompact
# 결측치 제거하고 분석하기 : 제거 -> drv(구동방식)에 따라 hwy 평균이 어떻게 다른지 알아보기

mpg.dropna(subset = ['hwy']) \
   .groupby('drv') \
   .agg(mean_hwy = ('hwy', 'mean'))
mean_hwy
drv
4 19.174757
f 27.728155
r 21.000000

[개인 실습] 혼자서 해보기(194쪽)

  • 이상치가 들어 있는 mpg 데이터를 이용해 분석 문제를 해결해 보세요
# mpg 데이터불러와  일부러 이상치 작성: drv(구동 방식) 변수의 값은 4(사륜구동), f(전륜구동), r(후륜구동) 세 종류. 몇 개의 행에 존재할 수 없는 값 k를 할당
# cty(도시 연비) 변수도 몇 개의 행에 극단적으로 크거나 작은 값을 할당

# mpg 데이터 불러오기
mpg = pd.read_csv('mpg.csv')

# drv 이상치 할당
mpg.loc[[9, 13, 57, 92], 'drv'] = 'k'

# cty 이상치 할당
mpg.loc[[28, 42, 128, 202], 'cty'] = [3, 4, 39, 42]
mpg
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20 31 p compact
3 audi a4 2.0 2008 4 auto(av) f 21 30 p compact
4 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact
... ... ... ... ... ... ... ... ... ... ... ...
229 volkswagen passat 2.0 2008 4 auto(s6) f 19 28 p midsize
230 volkswagen passat 2.0 2008 4 manual(m6) f 21 29 p midsize
231 volkswagen passat 2.8 1999 6 auto(l5) f 16 26 p midsize
232 volkswagen passat 2.8 1999 6 manual(m5) f 18 26 p midsize
233 volkswagen passat 3.6 2008 6 auto(s6) f 17 26 p midsize

234 rows × 11 columns

# 구동방식(drv)별로 도시 연비가 어떻게 다른지 알아보려 한다. 분석 하기 전에 우선 두 변수에 이상치가 있는지 확인하려 한다.

Q1: drv에 이상치 있는지 확인. 이상치를 결측 처리한 다음 이상치가 사라졌는지 확인. 결측 처리할 때는 df.isin()을 활용하라

# 이상치 확인
mpg['drv'].value_counts().sort_index()
drv
4    100
f    106
k      4
r     24
Name: count, dtype: int64
# 결측치 처리
import numpy as np
mpg['drv'] = np.where(mpg['drv'].isin(['4', 'f', 'r']), mpg['drv'], np.nan)
mpg = mpg.dropna(subset = ['drv'])
mpg
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20 31 p compact
3 audi a4 2.0 2008 4 auto(av) f 21 30 p compact
4 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact
... ... ... ... ... ... ... ... ... ... ... ...
229 volkswagen passat 2.0 2008 4 auto(s6) f 19 28 p midsize
230 volkswagen passat 2.0 2008 4 manual(m6) f 21 29 p midsize
231 volkswagen passat 2.8 1999 6 auto(l5) f 16 26 p midsize
232 volkswagen passat 2.8 1999 6 manual(m5) f 18 26 p midsize
233 volkswagen passat 3.6 2008 6 auto(s6) f 17 26 p midsize

230 rows × 11 columns

# 이상치 여부 확인
mpg['drv'].value_counts().sort_index()
drv
4    100
f    106
r     24
Name: count, dtype: int64

Q2: 상자 그림 이용해 cty에 이상치 있는지 확인하라.

  • 상자 그림 기준으로 정상 범위를 벗어난 값을 결측 처리한 다음 다시 상자 그림을 만들어 이상치가 사라졌는지 확인하라
# 상자 그림을 이용해 cty에 이상치가 있는지 확인하라
import seaborn as sns
sns.boxplot(data = mpg, y = 'cty')
<Axes: ylabel='cty'>

# 상자 그림 기준으로 정상 범위 벗어난 값을 결측 처리하라

pct25 = mpg['cty'].quantile(.25)
pct75 = mpg['cty'].quantile(.75)
iqr = pct75 - pct25
lowest = pct25 - iqr * 1.5
highest = pct75 + iqr * 1.5
print(lowest)
print(highest)
6.5
26.5
mpg = mpg.copy()
mpg['cty'] = np.where((mpg['cty'] < 6.5)|(mpg['cty'] > 26.5), np.nan, mpg['cty'])
mpg
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18.0 29 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21.0 29 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20.0 31 p compact
3 audi a4 2.0 2008 4 auto(av) f 21.0 30 p compact
4 audi a4 2.8 1999 6 auto(l5) f 16.0 26 p compact
... ... ... ... ... ... ... ... ... ... ... ...
229 volkswagen passat 2.0 2008 4 auto(s6) f 19.0 28 p midsize
230 volkswagen passat 2.0 2008 4 manual(m6) f 21.0 29 p midsize
231 volkswagen passat 2.8 1999 6 auto(l5) f 16.0 26 p midsize
232 volkswagen passat 2.8 1999 6 manual(m5) f 18.0 26 p midsize
233 volkswagen passat 3.6 2008 6 auto(s6) f 17.0 26 p midsize

230 rows × 11 columns

mpg = mpg.dropna(subset = ['cty'])
# 상자 그림에서 이상치가 사라졌는지 확인하라
sns.boxplot(data = mpg, y = 'cty')
<Axes: ylabel='cty'>

# 이상치 제거 후 drv별로 cty 평균이 어떻게 다른지 알아보라. 하나의 pandas 구문으로 만들어라
mpg.dropna(subset = ['drv', 'cty']) \
   .groupby('drv') \
   .agg(mean_cty = ('cty', 'mean'))
mean_cty
drv
4 14.247423
f 19.470000
r 13.958333

08. 그래프 만들기

  • 데이터를 그래프로 표현하면 특징을 쉽게 이해할 수 있다.

08-1. 파이썬으로 만들 수 있는 그래프 살펴보기(197-198쪽)

  • 그래프 : 데이터를 보기 쉽게 그림으로 표현한 것

  • 데이터를 그래프로 표현하면 추세와 경향성이 드러나기 때문에 특징을 쉽게 이해할 수 있고, 그래프를 만드는 과정에서 새로운 패턴을 발견하기도 한다.

  • 분석 결과를 발표할 때, 그래프를 활용하면 데이터의 특징을 잘 전달할 수 있다.

  • seaborn은 그래프를 만들 때 많이 사용하는 패키지

08-2. 산점도 - 변수 간 관계 표현하기(199-204쪽)

  • 산점도(scatter plot) : 데이터를 x축과 y축에 점으로 표현한 그래프

  • 나이와 소득처럼 연속값으로 된 두 변수의 관계를 표현할 때 사용

[Do it! 실습] 산점도 만들기(199쪽)

  • sns.scatterplot() 이용

  • data에 그래프를 그리는 데 사용할 데이터 프레임을 입력,

  • x축과 y축에 사용할 변수를 ‘‘를 이용해 문자 형태로 입력

# mpg 데이터 불러옴

import pandas as pd
mpg = pd.read_csv('mpg.csv')
mpg.head()
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20 31 p compact
3 audi a4 2.0 2008 4 auto(av) f 21 30 p compact
4 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact
# x축은 displ, y축은 hwy를 나타낸 산점도 만들기

import seaborn as sns
sns.scatterplot(data = mpg, x = 'displ', y = 'hwy')
<Axes: xlabel='displ', ylabel='hwy'>

축 범위 설정하기

  • 필요성 : 데이터 전체가 아니라 일부만 표현하고 싶을 때 사용

  • sns.set()의 xlim과 ylim 이용해 설정

# x축 범위를 3-6으로 제한
sns.scatterplot(data = mpg, x = 'displ', y = 'hwy') \
   .set(xlim = [3, 6])
[(3.0, 6.0)]

# 같은 방식으로 ylim을 이용하면 y축 범위를 제한할 수 있다.
sns.scatterplot(data = mpg, x = 'displ', y = 'hwy') \
   .set(xlim = [3, 6], ylim = [10, 30])
[(3.0, 6.0), (10.0, 30.0)]

종류별로 표식 색깔 바꾸기

  • hue 이용
# drv(구동 방식)별로 표식 색깔 다르게 표현
sns.scatterplot(data = mpg, x = 'displ', y = 'hwy', hue = 'drv')
<Axes: xlabel='displ', ylabel='hwy'>

# 그래프 활용하기(202쪽)
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 그래프 설정 변경 (기본값 : dpi = 72, figsize = [6, 4], size = 10, font = sans-serif)
'''
plt.rcParams.update({'figure.dpi'     : '100',
                     'figure.figsize' : [6, 4],
                     'font.size'      : '10',
                     'font.family'    : 'Malgun Gothic'})
'''

plt.rcParams.update({'font.family'    : 'Malgun Gothic'})

[개인 실습] 혼자서 해보기(204쪽)

  • mpg 데이터와 midwest 데이터를 이용해 분석 문제를 해결해 보세요

Q1: mpg 데이터의 cty와 hwy 간 관계 - 산점도

# x축은 cty, y축은 hwy로 된 산점도
mpg = pd.read_csv('mpg.csv')
sns.scatterplot(data = mpg, x = 'cty', y = 'hwy')
<Axes: xlabel='cty', ylabel='hwy'>

Q2: midwest에서 전체 인구와 아시아인 인구 간의 관계 - 산점도

  • x축은 poptotal(전체 인구), y축은 popasian(아시아인 인구)

  • 단, 전체 인구는 50만 명 이하, 아시아인 인구는 1만 명 이하인 지역만 산점도에 표시되게 설정하라

midwest = pd.read_csv('midwest.csv')
midwest.head(3)
PID county state area poptotal popdensity popwhite popblack popamerindian popasian ... percollege percprof poppovertyknown percpovertyknown percbelowpoverty percchildbelowpovert percadultpoverty percelderlypoverty inmetro category
0 561 ADAMS IL 0.052 66090 1270.961540 63917 1702 98 249 ... 19.631392 4.355859 63628 96.274777 13.151443 18.011717 11.009776 12.443812 0 AAR
1 562 ALEXANDER IL 0.014 10626 759.000000 7054 3496 19 48 ... 11.243308 2.870315 10529 99.087145 32.244278 45.826514 27.385647 25.228976 0 LHR
2 563 BOND IL 0.022 14991 681.409091 14477 429 35 16 ... 17.033819 4.488572 14235 94.956974 12.068844 14.036061 10.852090 12.697410 0 AAR

3 rows × 28 columns

sns.scatterplot(data = midwest, x = 'poptotal', y = 'popasian') \
   .set(xlim = [0, 500000], ylim = [0, 10000])
[(0.0, 500000.0), (0.0, 10000.0)]

08-3. 막대 그래프 - 집단 간 차이 표현하기(205-211쪽)

  • 막대그래프(bar chart) : 데이터의 크기를 막대의 길이로 표현한 그래프

  • 성별 소득 차이처럼 집단 간 차이를 표현할 때 자주 사용

[Do it! 실습] 평균 막대 그래프 만들기(205쪽)

  • 평균 막대 그래프 : 평균값의 크기를 막대 길이로 표현한 그래프

집단별 평균표 만들기

# drv(구동 방식)별 hwy(고속도로 연비) 평균
df_mpg = mpg.groupby('drv') \
            .agg(mean_hwy = ('hwy', 'mean'))
df_mpg
mean_hwy
drv
4 19.174757
f 28.160377
r 21.000000
# drv(구동 방식)별 hwy(고속도로 연비) 평균 
# seaborn 그래프 위해서는, 위 결과에서 drv가 인덱스 아닌 변수 값으로 나오게 해야 함
# df.groupby()에 as_index = False 입력하면 됨

df_mpg = mpg.groupby('drv', as_index = False) \
            .agg(mean_hwy = ('hwy', 'mean'))
df_mpg
drv mean_hwy
0 4 19.174757
1 f 28.160377
2 r 21.000000

그래프 만들기

  • sns.barplot() 이용

  • data에 데이터 프레임을 지정, x축에 범주를 나타낸 변수, y축에 평균값을 나타낸 변수를 지정

# drv별 hwy 평균을 나타낸 막대 그래프

sns.barplot(data = df_mpg, x = 'drv', y = 'mean_hwy');

크기순으로 정렬하기

  • 막대 정렬 순서 : 그래프 만드는데 사용한 데이터 프레임의 행 순서에 따름. ex) 4, f, r

  • 막대 크기 순서로 정렬 : df.sort_values() 이용

# 데이터 프레임 정렬하기
df_mpg = df_mpg.sort_values('mean_hwy', ascending = False)

# 막대 그래프 만들기
sns.barplot(data = df_mpg, x = 'drv', y = 'mean_hwy');

[Do it! 실습] 빈도 막대 그래프 만들기(208쪽)

  • 빈도 막대 그래프 : 값의 빈도(개수)를 막대 길이로 표현한 그래프

  • 여러 집단의 빈도를 비교할 때 자주 사용

집단별 빈도표 만들기

  • 빈도 막대 그래프에 사용될 데이터 : 집단별 빈도를 담은 데이터 프레임.

  • df.agg()에 빈도를 구하는 함수 count()를 적용 -> ‘구동 방식 별 빈도’ 담은 데이터 프레임

# 집단별 빈도표 만들기
df_mpg = mpg.groupby('drv', as_index = False) \
            .agg(n = ('drv', 'count'))
df_mpg
drv n
0 4 103
1 f 106
2 r 25

그래프 만들기

  • sns.barplot()
sns.barplot(data = df_mpg, x = 'drv', y = 'n');

sns.countplot()으로 빈도 막대 그래프 만들기

  • df.groupby()와 df.agg() 이용하는 작업 생략하고,

  • sns.countplot()로 곧바로 빈도 막대 그래프 만들 수 있다.

# 빈도 막대 그래프 만들기
sns.countplot(data = mpg, x = 'drv');

막대 정렬하기

  • order에 원하는 순서로 값을 입력해서 sns.countplot()으로 만든 그래프의 막대 정렬
# 4, f, r 순으로 막대 정렬
sns.countplot(data = mpg, x = 'drv', order = ['4', 'f', 'r']);

# drv 빈도가 높은 순으로 막대 정렬할 때
## order에 mpg['drv'].value_counts().index 입력 -> 빈도 내림차순 정렬
# drv의 값을 빈도가 높은 값에서 낮은 값으로 내림차순 정렬
mpg['drv'].value_counts().index
Index(['f', '4', 'r'], dtype='object', name='drv')
# drv 빈도를 내림차순으로 막대 정렬
sns.countplot(data = mpg, x = 'drv',
              order = mpg['drv'].value_counts().index);

[개인 실습] 혼자서 해보기(211쪽)

  • mpg 데이터를 이용해 분석 문제를 해결해 보세요

Q1: ‘suv’ 차종의 cty 평균이 가장 높은 회사 다섯 곳을 그래프로 표현

  • 연비가 높은 순으로 정렬
mpg.head(3)
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20 31 p compact
m_cty = mpg.query('category == "suv"') \
           .groupby('manufacturer', as_index = False) \
           .agg(mean_cty = ('cty', 'mean')) \
           .sort_values(by = 'mean_cty', ascending = False) \
           .head()
m_cty
manufacturer mean_cty
8 subaru 18.833333
9 toyota 14.375000
7 nissan 13.750000
3 jeep 13.500000
6 mercury 13.250000
# 막대그래프
sns.barplot(data = m_cty, x = 'manufacturer', y = 'mean_cty')
<Axes: xlabel='manufacturer', ylabel='mean_cty'>

Q2: 자동차 중에 어떤 category(자동차 종류)가 많은가?

  • 막대그래프 이용해 자동차 종류별 빈도 표현하라 (빈도 높은 것부터 정렬)
df = mpg.groupby('category', as_index = False) \
        .agg(freq_cgy = ('category', 'count')) \
        .sort_values(by = 'freq_cgy', ascending = False)
df
category freq_cgy
6 suv 62
1 compact 47
2 midsize 41
5 subcompact 35
4 pickup 33
3 minivan 11
0 2seater 5
sns.barplot(data = df, x = 'category', y = 'freq_cgy')
<Axes: xlabel='category', ylabel='freq_cgy'>

08-4. 선 그래프 - 시간에 따라 달라지는 데이터 표현하기(212-217쪽)

  • 선 그래프 : 데이터를 선으로 표현한 그래프. 시간에 따라 달라지는 데이터를 표현할 때 자주 사용.

    • 예) 환율, 주가지수 등 경제지표가 시간에 따라 변하는 양상

    • 시계열 데이터 : 일별 환율처럼, 일정 시간 간격을 두고 나열된 데이터

    • 시계열 그래프 : 시계열 데이터를 선으로 표현한 그래프

[Do it! 실습] 시계열 그래프 만들기(212쪽)

  • economics 데이터 : 미국의 여러 경제 지표를 월별로 나타낸 데이터

  • economics 데이터 이용해서 시간에 따라 실업자 수가 변하는 시계열 그래프 작성

  • economics 데이터 출처 : bit.ly/easypy_85

# economics 데이터 불러오기
import pandas as pd

economics = pd.read_csv('economics.csv')
print(economics.shape)
economics.head()
(574, 6)
date pce pop psavert uempmed unemploy
0 1967-07-01 506.7 198712.0 12.6 4.5 2944
1 1967-08-01 509.8 198911.0 12.6 4.7 2945
2 1967-09-01 515.6 199113.0 11.9 4.6 2958
3 1967-10-01 512.2 199311.0 12.9 4.9 3143
4 1967-11-01 517.4 199498.0 12.8 4.7 3066
# sns.lineplot() 이용하여 x축에는 시간을 나타낸 data, y축에는 실업자 수 나타낸 unemploy를 지정
import seaborn as sns
sns.lineplot(data = economics, x = 'date', y = 'unemploy');

x축에 연도 표시하기

  • 먼저 변수 타입을 날짜 시간 타입(datetime64)으로 변경해야 함

  • 현재 상태 : date가 문자(object) 타입으로 되어 있다

날짜 시간 타입 변수 만들기
  • pd.to_datetime() 이용하면 변수 타입을 날짜 시간 타입으로 변경 가능
# 날짜 시간 타입 변수 만들기
economics['date2'] = pd.to_datetime(economics['date'])

# 변수 타입 확인
economics.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 574 entries, 0 to 573
Data columns (total 7 columns):
 #   Column    Non-Null Count  Dtype         
---  ------    --------------  -----         
 0   date      574 non-null    object        
 1   pce       574 non-null    float64       
 2   pop       574 non-null    float64       
 3   psavert   574 non-null    float64       
 4   uempmed   574 non-null    float64       
 5   unemploy  574 non-null    int64         
 6   date2     574 non-null    datetime64[ns]
dtypes: datetime64[ns](1), float64(4), int64(1), object(1)
memory usage: 31.5+ KB
# 서로 다른 두 타입의 날짜 비교 : 값이 달라지진 않음
economics[['date', 'date2']]
date date2
0 1967-07-01 1967-07-01
1 1967-08-01 1967-08-01
2 1967-09-01 1967-09-01
3 1967-10-01 1967-10-01
4 1967-11-01 1967-11-01
... ... ...
569 2014-12-01 2014-12-01
570 2015-01-01 2015-01-01
571 2015-02-01 2015-02-01
572 2015-03-01 2015-03-01
573 2015-04-01 2015-04-01

574 rows × 2 columns

# 변수가 날짜 시간 타입으로 되어 있으면 df.dt를 이용해 연, 월, 일을 추출할 수 있다
# 연 추출
economics['date2'].dt.year
0      1967
1      1967
2      1967
3      1967
4      1967
       ... 
569    2014
570    2015
571    2015
572    2015
573    2015
Name: date2, Length: 574, dtype: int32
# 월 추출
economics['date2'].dt.month
0       7
1       8
2       9
3      10
4      11
       ..
569    12
570     1
571     2
572     3
573     4
Name: date2, Length: 574, dtype: int32
# 일 추출
economics['date2'].dt.day
0      1
1      1
2      1
3      1
4      1
      ..
569    1
570    1
571    1
572    1
573    1
Name: date2, Length: 574, dtype: int32

연도 변수 만들기

# 연도 변수 추가
economics['year'] = economics['date2'].dt.year
economics.head()
date pce pop psavert uempmed unemploy date2 year
0 1967-07-01 506.7 198712.0 12.6 4.5 2944 1967-07-01 1967
1 1967-08-01 509.8 198911.0 12.6 4.7 2945 1967-08-01 1967
2 1967-09-01 515.6 199113.0 11.9 4.6 2958 1967-09-01 1967
3 1967-10-01 512.2 199311.0 12.9 4.9 3143 1967-10-01 1967
4 1967-11-01 517.4 199498.0 12.8 4.7 3066 1967-11-01 1967

x축에 연도 표시하기

# x축에 연도 표시
sns.lineplot(data = economics, x = 'year', y = 'unemploy');

# 신뢰구간을 표시하지 않으려면 ci = None를 입력
sns.lineplot(data = economics, x = 'year', y = 'unemploy', ci = None);
C:\Users\Public\Documents\ESTsoft\CreatorTemp\ipykernel_564812\2298223364.py:2: FutureWarning: 

The `ci` parameter is deprecated. Use `errorbar=None` for the same effect.

  sns.lineplot(data = economics, x = 'year', y = 'unemploy', ci = None);

sns.lineplot(data = economics, x = 'year', y = 'unemploy', errorbar = None);

[개인 실습] 혼자서 해보기(217쪽)

  • economics.csv 데이터를 이용해 분석 문제를 해결해 보세요

Q1: psvert(개인 저축률)의 연도별 변화

  • psvert가 시간에 따라 어떻게 변화했나. 연도별 개인 저출률 변화를 나타내는 시계열 그래프를 그려라
# 데이터 첫 부분 3행 파악
economics.head(3)
date pce pop psavert uempmed unemploy date2 year
0 1967-07-01 506.7 198712.0 12.6 4.5 2944 1967-07-01 1967
1 1967-08-01 509.8 198911.0 12.6 4.7 2945 1967-08-01 1967
2 1967-09-01 515.6 199113.0 11.9 4.6 2958 1967-09-01 1967
# 선 그래프 그리기
sns.lineplot(data = economics, x = 'year', y = 'psavert', errorbar = None);

Q2: psavert의 2014년 월별 변화 그래프

# 변수 타입 확인
economics.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 574 entries, 0 to 573
Data columns (total 8 columns):
 #   Column    Non-Null Count  Dtype         
---  ------    --------------  -----         
 0   date      574 non-null    object        
 1   pce       574 non-null    float64       
 2   pop       574 non-null    float64       
 3   psavert   574 non-null    float64       
 4   uempmed   574 non-null    float64       
 5   unemploy  574 non-null    int64         
 6   date2     574 non-null    datetime64[ns]
 7   year      574 non-null    int32         
dtypes: datetime64[ns](1), float64(4), int32(1), int64(1), object(1)
memory usage: 33.8+ KB
# 월 정보를 산출하여 파생변수 df_2014에 저장하라
df_2014 = economics.assign(month = lambda x: x['date2'].dt.month) \
                   .query('year == 2014')
df_2014
date pce pop psavert uempmed unemploy date2 year month
558 2014-01-01 11512.5 317593.923 7.1 15.4 10202 2014-01-01 2014 1
559 2014-02-01 11566.2 317753.883 7.3 15.9 10349 2014-02-01 2014 2
560 2014-03-01 11643.0 317917.203 7.4 15.8 10380 2014-03-01 2014 3
561 2014-04-01 11702.6 318089.218 7.4 15.7 9702 2014-04-01 2014 4
562 2014-05-01 11748.4 318269.505 7.4 14.6 9859 2014-05-01 2014 5
563 2014-06-01 11817.0 318464.152 7.4 13.8 9460 2014-06-01 2014 6
564 2014-07-01 11860.5 318662.368 7.5 13.1 9608 2014-07-01 2014 7
565 2014-08-01 11944.3 318893.786 7.2 12.9 9599 2014-08-01 2014 8
566 2014-09-01 11957.4 319125.296 7.4 13.4 9262 2014-09-01 2014 9
567 2014-10-01 12023.0 319353.734 7.2 13.6 8990 2014-10-01 2014 10
568 2014-11-01 12051.4 319564.209 7.3 13.0 9090 2014-11-01 2014 11
569 2014-12-01 12062.0 319746.157 7.6 12.9 8717 2014-12-01 2014 12
# 2014년 월별 변화 그래프를 그려라
sns.lineplot(data = df_2014, x = 'month', y = 'psavert', errorbar = None);

08-5. 상자 그림 - 집단 간 분포 차이 표현하기(218-220쪽)

  • 상자 그림(box plot): 데이터의 분포 또는 퍼져 있는 형태를 직사각형 상자 모양으로 표현한 그래프.

  • 평균값을 볼 때보다 데이터의 특징을 더 자세히 이해할 수 있다.

[Do it! 실습] 상자 그림 만들기(218쪽)

# mpg로 구동 방식별 고속도로 연비를 상자 그림으로 표현: 값 "자체" > 값의 개수
mpg = pd. read_csv('mpg.csv')
sns.boxplot(data = mpg, x = 'drv', y = 'hwy');

# 상자 그림 이해하기
# f 방식 자동차의 hwy 연비"값" 분포도
mpg.query('drv == "f"') \
   .groupby('hwy') \
   .agg(n = ('hwy', 'count')) \
   .sort_index(ascending = False)
n
hwy
44 2
41 1
37 1
36 2
35 2
34 1
33 2
32 4
31 7
30 4
29 22
28 6
27 10
26 22
25 3
24 9
23 3
22 3
21 1
17 1
# 정상 범위 벗어난 값

mpg_1 = mpg[['drv', 'hwy']] \
        .query('drv == "f"')
pct25 = mpg_1['hwy'].quantile(.25)
pct75 = mpg_1['hwy'].quantile(.75)
iqr = pct75 - pct25
lowest = pct25 - iqr * 1.5  # 하한
highest = pct75 + iqr * 1.5 # 상한
print(lowest)
print(highest)
21.5
33.5

[개인 실습] 혼자서 해보기(220쪽)

  • mpg 데이터를 이용해 분석 문제를 해결해 보세요

Q1: 자동차 종류별 도시 연비 비교

  • category(자동차 종류)가 compact, subcompact, suv인 자동차의 cty(도시 연비)가 어떻게 다른지 비교해 보려 한다. 세 차종의 cty를 나타낸 상자 그림을 만들어라
# 세 차종만으로 된 데이터 프레임을 변수 result에 저장하라
result = mpg.query('category.isin(["compact", "subcompact", "suv"])')
result
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20 31 p compact
3 audi a4 2.0 2008 4 auto(av) f 21 30 p compact
4 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact
... ... ... ... ... ... ... ... ... ... ... ...
222 volkswagen new beetle 1.9 1999 4 auto(l4) f 29 41 d subcompact
223 volkswagen new beetle 2.0 1999 4 manual(m5) f 21 29 r subcompact
224 volkswagen new beetle 2.0 1999 4 auto(l4) f 19 26 r subcompact
225 volkswagen new beetle 2.5 2008 5 manual(m5) f 20 28 r subcompact
226 volkswagen new beetle 2.5 2008 5 auto(s6) f 20 29 r subcompact

144 rows × 11 columns

# 위 세 자동차의 도시 연비를 상자 그림으로 나타내어라
sns.boxplot(data = result, x = 'category', y = 'cty');

The End of Notebook

업데이트:

댓글남기기