파이썬-데이터-시각화-기초-seaborn-씨본
Seaborn의 1차원 실수형 데이터 시각화 함수 종류와 그래프

Seaborn은 파이썬(Python)의 대표적인 데이터 시각화 라이브러리입니다. Seaborn의 기본적인 시각화 기능은 Matplotlib을 기반으로 만들어졌습니다. Seaborn의 가장 큰 장점은 문법적 간결성입니다. Seaborn을 사용하면 비교적 짧은 코드로도 통계학의 주요 그래프를 빠르고 간편하게 만들 수 있습니다. 그래서 데이터 사이언스 전문가들은 데이터 시각화를 처음 시작하는 분들에게 Seaborn을 추천하곤 합니다.

이번 시간에는 Seaborn의 기초 사용법을 알아보겠습니다. 기초편에서는 Seaborn을 설치하고 기본적인 환경 설정을 하는 법과 1차원 데이터를 시각화하는 법을 다룹니다. 심화편에서는 2차원과 다차원 그래프를 시각화하는 법을 살펴보겠습니다.

다음은 Seaborn에서 1차원 데이터를 시각화할 때 사용할 수 있는 함수와 각 함수가 그리는 그래프를 나타낸 그림입니다. 그럼 파이썬 Seaborn으로 데이터 시각화하기 함께 시작해볼까요?

파이썬-데이터-시각화-라이브러리-1차원-데이터-함수-그래프
Seaborn에서 1차원 데이터를 시각화하는데 쓰이는 함수와 각 함수에 특화된 그래프 | Snug Archive

안내 사항

Seaborn으로 데이터를 시각화하기 위해서는 몇 가지 준비가 필요합니다. 첫째, 실습 환경입니다. 대표적인 데이터 사이언스 통합개발환경(IDE)으로는 스파이더(Spyder), 아톰(Atom), 파이참(PyCharm) 등이 있습니다. 이 글에서는 주피터 노트북(Jupyter Notebook)을 사용합니다. 주피터 노트북의 환경 설정이 필요하신 분들은 주피터 노트북 환경 설정하기를 참조해주세요.

둘째, 통계 용어에 대한 간단한 이해가 필요합니다. 이 글에는 통계 용어가 자주 사용됩니다. 각 용어는 간략히 설명할 예정이나, 개념에 대한 구체적인 설명이나 수식은 다루지 않습니다. 만약, 통계 용어를 참조하면서 글을 읽고 싶으시다면, 확률과 통계 핵심 개념과 용어를 함께 읽으시기를 권해드립니다.

셋째, Seaborn의 함수의 종류입니다. Seaborn 함수는 그래프 수준(figure-level) 함수와 축 수준(axes-level) 함수로 나뉩니다. 그래프 수준 함수는 상위 함수로 해당 함수에 옵션을 사용해 그래프의 종류를 지정합니다. 반면 축 수준 함수는 각 그래프의 종류에 특화된 함수입니다. 축 수준 함수는 함수마다 1가지 그래프를 그리는데 맞춤화되어 있습니다.

사용하는 옵션이 서로 다른 경우도 있지만 보통 그래프 수준 함수와 축 수준 함수의 옵션은 호환 가능합니다. 다만, Matplotlib과의 호환성이나 한 그래프 위에 다른 그래프를 겹쳐 그릴 수 있다는 점에서 축 수준의 함수가 그래프 수준 함수보다 조금 더 유연합니다. 여기서는 그래프 수준 함수를 중심으로 그래프를 살펴보되, 그래프 수준으로 그릴 수 없는 것은 축 수준 함수로 그리겠습니다.

그럼 Seaborn 설치와 환경 설정부터 시작해보겠습니다.

설치 및 환경 설정

1) 명령어

Seaborn 패키지를 설치하려면 파이썬의 패키지 관리 시스템인 pip을 사용하면 됩니다. 설치를 위해서 아래 코드를 터미널에 입력해주세요.

python
pip install seaborn

파이썬/R 배포판인 아나콘다(Anaconda)로 작업하시는 분들은 아래와 같이 conda 명령어를 사용하여 Seaborn을 설치하시면 됩니다.

python
conda install seaborn

Seaborn 설치를 완료하셨다면, 패키지가 잘 설치되어 있는지 확인해보겠습니다. 사용하시는 IDE 또는 주피터노트북에 다음 코드를 입력해주세요.

python
import seaborn as sns
df = sns.load_dataset("penguins")
sns.pairplot(df, hue="species")

코드를 실행했을 때 다음과 같은 데이터 그래프가 만들어졌다면 Seaborn 라이브러리가 잘 설치된 것입니다.

파이썬-데이터-시각화-seaborn-테스트-데이터
Seaborn 테스트 데이터 | Snug Archive

Seaborn 설치를 완료하셨다면 다음은 라이브러리를 임포트(import)하겠습니다.

2) 라이브러리 임포트

Seaborn 라이브러리를 실행하기 위해서는 몇 가지 라이브러리를 함께 실행해야합니다. Seaborn 패키지가 이들 라이브러리에 의존하고 있기 때문이죠. 여기에 추가로 warnings.filterwarnings('ignore')을 이용해 경고창을 사용하지 않도록 설정하겠습니다. 다음 코드를 실행해 환경 설정을 진행해주세요.

python
# 필수 라이브러리 준비
import numpy as np # Numpy(넘파이) 패키지 임포트
import pandas as pd # pandas(판다스) 패키지 임포트
import matplotlib.pyplot as plt # Matplotlib(맷플롯립) 패키지의 pyplot 모듈을 plt로 임포트
import seaborn as sns # Seaborn(시본) 패키지를 sns로 임포트
# 경고창 사용하지 않기
import warnings
warnings.filterwarnings('ignore')

3) 한글 환경 설정

Seaborn에서 한글이 깨지는 현상을 방지하려면 아래와 같이 Matplotlib의 rcParams를 이용해 폰트와 축의 마이너스 기호 사용 여부를 지정해주어야 합니다. 자세한 사항은 Matplotlib 사용법(예정)을 참조해주세요.

python
from matplotlib import rcParams
rcParams['font.family'] = 'Malgun Gothic' # Windows
# rcParams['font.family'] = 'AppleGothic' # Mac
rcParams['axes.unicode_minus'] = False # 한글 폰트 사용 시, 마이너스 글자가 깨지는 현상 방지

4) 테마

Seaborn에는 set_style 함수를 사용해 기본 테마(darkgrid, whitegrid, dark, white, ticks)를 지정할 수 있습니다. 예제 코드는 다음과 같습니다.

python
sns.set_style("whitegrid")

여기서는 따로 테마를 지정하지 않겠습니다. 스타일링과 관련해 더 자세한 내용을 알고 싶은 분들은 Seaborn Asthetics 튜토리얼을 참고하시면 됩니다. 설치와 환경 설정을 모두 마쳤다면 이제 데이터를 로딩(loading)해오겠습니다.

5) 그래프 스타일링

그래프의 제목(title)이나 눈금(ticks), 라벨(labels) 등 그래프에 대한 세부 설정은 Matplotlib을 이용하면 됩니다.

python
plt.title("제목") # 그래프 제목 설정
rcParams['font.size'] # 폰트 사이즈 설정
rcParams['figure.figsize'] = 15,8 # 그래프 크기 설정

Matplotlib 사용법은 파이썬 데이터 시각화 Matplotlib 사용법을 참고해주세요. 그럼 지금부터는 데이터를 준비해보겠습니다.

데이터 준비

Seaborn에서는 데이터를 외부에서 가져올 수도 있고, 내장 데이터(built-in data)를 사용할 수도 있습니다. 외부 데이터를 사용하시려면 pandas를 이용해 데이터를 가져오시면 됩니다. pandas로 데이터를 로딩해오고 싶은 분들은 Python pandas 데이터 생성, 로딩 및 저장, 색인 관리하는 법에서 '로딩 및 저장'편을 참조해주세요. 여기서는 Seaborn의 내장 데이터를 사용하겠습니다.

Seaborn 패키지 내에 어떤 내장 데이터셋이 있는지 알아보려면 get_dataset_names 메서드(methods)를 이용하면 됩니다. 코드는 다음과 같습니다.

python
sns.get_dataset_names()
# 결과
['anagrams', 'anscombe', 'attention', 'brain_networks', 'car_crashes', 'diamonds',
'dots', 'exercise', 'flights', 'fmri', 'gammas', 'geyser', 'iris', 'mpg',
'penguins', 'planets', 'taxis', 'tips', 'titanic']

이 데이터셋 중에서 몇 가지를 선택해서 데이터를 가져와 보도록 하겠습니다. 데이터를 로딩하려면 load_dataset 함수를 사용하면 됩니다. 여기서는 다음 데이터셋을 불러와보겠습니다.

python
penguins = sns.load_dataset("penguins") # 펭귄 데이터
tips = sns.load_dataset("tips") # 팁 데이터
diamonds = sns.load_dataset("diamonds") # 다이아몬드 데이터
titanic = sns.load_dataset("titanic") # 타이타닉호 데이터
planets = sns.load_dataset("planets") # 행성 데이터

데이터셋이 잘 준비되었다면 이제 본격적으로 시각화를 해보겠습니다. 우리가 시각화할 데이터는 1차원 데이터입니다. 1차원 데이터란 속성(attribute)이 1개인 데이터, Numpy 배열에서 원소를 한 줄로 나타낼 수 있는 데이터, 엑셀에서 속성을 나타내는 열(columns)이 1개이고 데이터 레코드(data records)를 나타내는 행(rows)만 여러 개인 데이터, 독립변수(independent variable) 또는 변량(variate)이 1개인 데이터라 볼 수 있습니다.

1차원 데이터는 실수형과 범주형으로 나뉩니다. 실수형은 변수가 실숫값인 연속적 변수(continous variables)입니다. 이산적 변수(discrete variables)도 실수형에 포함됩니다. 범주형은 변수가 카테고리(category)처럼 분류된 질적 변수(qualitative variables)를 의미합니다. 그럼 1차원 실수형 데이터부터 시각화해보겠습니다.

1차원 실수형 데이터 시각화

데이터를 살펴볼 때 가장 먼저 하면 좋은 일은 데이터의 분포(distributions)를 파악하는 일입니다. 데이터의 분포를 파악한다는 것은 관찰된 자료가 어느 위치에 집중되어 있는지(집중화경향), 자료는 얼마나 흩어져 있는지(분산도), 자료가 한쪽에 몰려있지는 않은지 (비대칭도), 평균에서 극단적으로 벗어난 값(이상치)가 있지는 않은지를 살펴보는 일입니다.

데이터의 범위가 매우 크다면 이상점(outliers)을 제외시키는 것이 좋습니다. 이상치를 제거하지 않으면, 데이터가 뭉쳐 보일 수 있습니다. 만약, 극단값을 포함해서 데이터를 시각화할 경우에는 로그 스케일로 변환해주면 정확한 결과를 도출할 수 있습니다.

수치형 자료를 시각화하는 대표적인 방법은 점그래프(dot plot), 상자그림(box plot), 히스토그램(histogram)입니다. 여기서는 데이터의 실제 위치를 점으로 나타낸 1) 점그래프(dot plot)와 선분으로 나타낸 2) 선분그래프(rug plot), 데이터의 이상점을 확인하는데 용이한 3) 상자그림, 데이터 관측수가 많아서 점그래프 또는 선그래프만으로는 데이터의 분포를 파악하기 어려울 때 데이터의 구간을 나누어 분포를 파악하는 4) 단변량 히스토그램(univariate histogram), 그룹별 비교를 위해 단변량 히스토그램을 2가지 방법으로 정규화한 정규 히스토그램(normalized histogram), 5) 히스토그램의 불연속성을 개선한 방법인 커널밀도추정(kernel density estimation, KDE)으로 그린 확률밀도함수(probability density function, PDF), 마지막으로 6) 확률밀도함수를 적분한 누적분포함수(cumulative distribution function, CDF) 순으로 알아보겠습니다.

1) 점그래프

점그래프(동의어: dot graph, strip chart, 점 도표)는 데이터의 위치를 점(dots)으로 보여줍니다. 점그래프는 데이터의 실제 위치를 파악하는데 유용합니다. 점그래프를 그리려면 stripplot 함수를 이용하거나, catplot을 이용하면 됩니다. 코드는 다음과 같습니다.

python
sns.stripplot(data=iris, x="sepal_length") # sns.stripplot(x=iris["sepal_length"])
sns.catplot(data=iris, x="sepal_length")
파이썬-데이터-시각화-seaborn-dotplot
dotplot으로 그린 점 그래프 | Snug Archive

2) 선분그래프

선분그래프(rug plot) 또는 러그 플롯은 데이터 포인트를 축 위에 작은 선분(rug)로 나타내어 실제 데이터들의 위치를 보여줍니다. 점그래프와 마찬가지로 선분그래프도 데이터의 실제 위치를 파악하기 좋습니다. 러그 플롯을 그리려면 displot 함수에 rug=True 옵션을 이용하거나 rugplot 함수를 사용하면 됩니다. 러그를 세부적으로 조정해야 할 때는 displot 함수보다는 rugplot 함수를 사용하는 것이 좋습니다.

  • height: 선분 길이 지정
  • clip_on: 선분 축 밖에 그리기 지정
  • lw: 선분 얇기 지정
  • alpha: 선분 투명도 지정
python
# 코드1: 선분 그리기
sns.displot(data=tips, x="total_bill", rug=True)
# 코드2: 높이 조정한 선분 그리기
sns.rugplot(data=tips, x="total_bill", height=.1)
# 코드3: 선분 축 밖에 그리기
sns.rugplot(data=tips, x="total_bill", height=-.02, clip_on=False)
# 코드4: 선분 얇게 그리기 & 투명도 추가
sns.rugplot(data=diamonds, x="carat", lw=1, alpha=.005)
파이썬-데이터-시각화-seaborn-rugplot
rugplot함수로 그린 다양한 선분그래프 | Snug Archive

3) 상자그림

상자그림(동의어: box plot, 박스 플롯, 박스 그래프, 상자 그래프)은 데이터의 5가지 통계량(최솟값, 제 1사분위, 제 2사분위, 제 3사분위, 최댓값)을 나타내는 그래프입니다. 상자그림은 데이터의 전체적인 분포와 이상치를 확인하는데 유용합니다. 상자그림을 그리려면 boxplot 함수 또는 catplot 함수에 kind="box" 옵션을 주면 됩니다. 코드는 다음과 같습니다.

python
# 코드1
sns.boxplot(data=iris, x="sepal_length") # sns.boxplot(x=tips["sepal_length"])과 동일
sns.catplot(data=iris, x="sepal_length", kind="box")
# 코드2
sns.boxplot(data=iris, orient="h")
sns.catplot(data=iris, orient="h", kind="box")
파이썬-데이터-시각화-seaborn-boxplot
boxplot으로 그린 상자수염 그래프 | Snug Archive

데이터가 많아질 경우 점그래프 또는 선분그래프만으로 데이터의 분포를 파악하기 어렵습니다. 많은 데이터 포인트들이 서로 겹쳐 보이기 때문입니다. 이때 사용하면 좋은 도구가 히스토그램입니다.

4) 단변량 히스토그램

히스토그램은 데이터를 몇 개의 구간으로 나눈 후 각 구간에 포함된 데이터의 개수 또는 도수(frequency)를 그림으로 나타낸 것입니다. 데이터가 구간으로 처리되기 때문에, 많은 데이터의 분포를 파악하는데 유용합니다.

변수가 1개인 단변량 히스토그램을 만들려면 displot 함수와 histplot 함수를 이용하면 됩니다. 여기서는 displot을 자세히 다루겠습니다.

displot 함수의 초기 기본 설정은 kind="hist"입니다. displot 함수를 사용할 때 kind 옵션을 주어 따로 그래프를 지정하지 않으면 히스토그램을 그립니다. 코드를 통해 살펴보겠습니다.

python
# 코드1
sns.displot(penguins, x="flipper_length_mm")
sns.displot(data=penguins, x="flipper_length_mm")
# 코드2
sns.displot(penguins['flipper_length_mm']) # pandas DataFrame을 인자로 사용

코드1은 단변량 히스토그램을 그립니다. 여기서 data를 명시할 수도 있고, 데이터명만 사용할 수도 있습니다. 그래프 수준 함수에서는 데이터명만 사용해도 되지만, 축 수준 함수에서는 data 매개변수(parameter)를 이용해 데이터 이름을 명시하는 것이 좋습니다. 코드2는 히스토그램과 해당 확률변수(random variables)에 대해 추정된 확률밀도함수도 함께 생성합니다. 두 코드를 실행하면 다음과 같은 그래프가 만들어집니다.

파이썬-데이터-시각화-seaborn-displot-기본-그래프-비교
displot 함수에 data 옵션을 사용한 것과 pandas의 데이터 프레임을 인자로 준 그래프 비교 | Snug Archive

그래프를 보면 각 등급(class)의 막대가 서로 붙어있는 것을 알 수 있습니다. 이는 penguins 데이터가 연속적 자료이기 때문입니다. 히스토그램에서는 변수가 연속적이라는 것을 보여주기 위해서 각 등급의 막대가 붙어 있습니다.

특정 조건

pandas를 이용하면 데이터를 조건별로 선택할 수 있습니다. 다음 코드는 'species'가 'Adelie'인 펭귄의 'flipper_length_mm'를 관측한 값에 대해 히스토그램과 확률밀도함수를 그리는 예제 코드입니다.

python
sns.displot(penguins[penguins['species'] == 'Adelie']['flipper_length_mm'])

등급수와 등급폭: bins(숫자), binwidth

히스토그램에서는 등급수 또는 등급폭에 따라 그래프의 모양이 달라집니다. displot 함수에서 등급수는 bins 옵션으로, 등급폭은 binwidth 옵션으로 지정합니다.

python
sns.displot(penguins, x="flipper_length_mm", bins=10) # 등급의 수를 10개로 지정
sns.displot(penguins, x="flipper_length_mm", binwidth=3) # 등급의 폭을 3으로 지정
파이썬-데이터-시각화-seaborn-displot-bins-binwidth-히스토그램
displot 함수에 각각 등급수와 등급폭을 지정해서 만든 히스토그램 | Snug Archive

히스토그램은 주로 연속적 자료를 시각화할 때 쓰이지만, 이산적 자료(discrete data)를 시각화하는데도 종종 사용합니다. 다만, 이산적 자료를 히스토그램을 이용해 막대그래프(bar graph)로 시각화할 때는 다음과 같은 조정이 필요합니다.

  • 등급 명시
  • 등급명이 막대의 중앙에 오도록 위치
  • 변수가 연속적이지 않고 이산적이라는 것을 알려주기 위해 등급과 등급 사이에 여유 두기

이를 도와주는 옵션이 각각 bins=리스트, discrete=True, shrink 입니다.

등급명, 등급명 위치, 등급 사이 공간 지정: bins=리스트, discrete=True, shrink

각 옵션이 수행하는 일은 다음과 같습니다.

  • bins=리스트: 그래프의 x축에 명시할 등급을 직접 지정
  • discrete=True: 각 등급이 막대 중앙에 오도록 위치
  • shrink: 각 막대 사이에 공간을 마련

예제 코드와 실행 결과는 다음과 같습니다.

python
# 코드1: 기본 설정(눈금의 위치 조정 필요)
sns.displot(tips, x="size")
# 코드2: 등급 한계 지정
sns.displot(tips, x="size", bins=[1, 2, 3, 4, 5, 6, 7])
# 코드3: 각 등급명을 막대그래프 중앙으로 이동
sns.displot(tips, x="size", discrete=True)
# 코드4: 등급명 중앙으로 이동한 뒤 등급 간 공간 마련
sns.displot(tips, x="size", discrete=True, shrink=.8)
파이썬-데이터-시각화-seaborn-displot-히스토그램-옵션-비교
displot 함수에 bins=리스트, discrete=True, shrink 옵션을 적용해서 만든 히스토그램 비교 | Snug Archive

위에서는 displot 함수를 사용해 몇몇 눈금이 생략되었습니다. histplot 함수를 이용하면 모든 눈금이 표시됩니다.

그룹별 색깔 구분: hue

그룹별로 구분되는 히스토그램을 그리려면 hue 옵션을 사용하면 됩니다. hue 옵션과 함께 사용할 수 있는 옵션은 다음과 같습니다.

  • hue 기본 옵션: 겹침
  • element="step" 옵션: 불투명 + 겹침 없애기
  • multiple="stack" 옵션: 누적
  • multiple="dodge": 다중
python
sns.displot(penguins, x="flipper_length_mm", hue="species") # 코드1
sns.displot(penguins, x="flipper_length_mm", hue="species", element="step") # 코드2
sns.displot(penguins, x="flipper_length_mm", hue="species", multiple="stack") # 코드3
sns.displot(penguins, x="flipper_length_mm", hue="sex", multiple="dodge") # 코드4
파이썬-데이터-시각화-seaborn-displot-hue-옵션-비교
displot 함수에 hue, element='step', multiple 옵션을 적용해서 만든 히스토그램 비교 | Snug Archive

그룹별 히스토그램은 서로 겹쳐서 보여 각 데이터의 분포를 파악하기 어려울 수 있습니다. 이때 도수분포다각형(frequency distribution polygon)을 사용하면 겹친 부분을 줄이고 더 정확하게 그룹별 분포를 확인할 수 있습니다.

  • log_scale=True: x축 값 로그 스케일로 변환
  • element="poly": 그래프를 분포다각형으로 지정
  • fill=False: 그래프 선 아래 색깔 채우지 않기
python
sns.displot(data=planets, x="distance", hue="method", log_scale=True,
element="poly", fill=False)
파이썬-데이터-시각화-seaborn-displot-log-scale-element-poly-fill-false-그래프
displot 함수에 log_scale=True, element='poly', fill=False 옵션으로 그린 그래프 | Snug Archive

한 캔버스(canvas) 내에 여러 그래프를 그리지 않고 그래프를 서로 다른 캔버스에 나누어서 그리고 싶다면 col 옵션을 사용하면 됩니다.

그룹별 캔버스 구분: col

col 옵션은 그래프를 개별 캔버스에 나누어 그려줍니다. 예제 코드와 실행 결과는 아래와 같습니다.

python
sns.displot(penguins, x="flipper_length_mm", col="sex") # 성별에 따라 구분
파이썬-데이터-시각화-seaborn-displot-hue-옵션-비교
displot 함수의 col 옵션을 사용한 그래프 | Snug Archive

huecol 옵션을 사용하면 동일한 변수에 대해 서로 구분되는 그래프를 그릴 수 있습니다. 하지만, 그룹별로 관측수가 다르면 그래프의 분포를 정확히 비교하기 어렵습니다. 비교할 기준점이 통일되지 않았기 때문입니다. 비교 기준점을 단일화하려면 정규화(normalization)가 필요합니다.

정규화는 모든 데이터 포인트(data point)가 동일한 정도의 스케일(중요도)로 해석되도록 만드는 과정입니다. 정규화는 모든 데이터 포인트의 중요도를 균등하게 만들기 때문에, 이상치를 지닌 특정 속성이 다른 속성을 지배하는 것을 방지합니다. 히스토그램을 정규화하면 정규 히스토그램이 됩니다. 정규화는 전체관측수로 할 수도 있고, 면적으로 할 수도 있습니다.

정규 히스토그램(전체관측수)

stat="probability 또는 stat="percent" 옵션은 각 등급의 빈도수를 전체관측수로 나눈 정규 히스토그램을 만듭니다. stat 옵션에 probability 인자를 주면 y축이 확률(probability)인 그래프가 그려집니다. percent 옵션을 사용하면 y축이 백분율(percent)인 그래프가 만들어집니다. 전자의 경우 막대들의 높이를 모두 더하면 1이 되고, 후자의 경우에는 100이 됩니다. 코드와 실행 결과는 다음과 같습니다.

python
# 코드1: y축이 비율
sns.displot(penguins, x="flipper_length_mm", hue="species", stat="probability")
# 코드2: y축이 백분율
sns.displot(penguins, x="flipper_length_mm", hue="species", stat="percent")
파이썬-데이터-시각화-seaborn-displot-stat-옵션-비교
displot 함수의 stat='probability'와 stat='percent' 옵션을 사용한 그래프 | Snug Archive

정규 히스토그램(면적)

stat="density" 옵션은 각 등급의 빈도수를 전체 관측치의 개수와 막대 너비(width)의 곱으로 나눈 정규 히스토그램을 만들어줍니다. 이 히스토그램에서 y축은 밀도(density)입니다. 각 막대의 넓이를 모두 더한 합은 1이 됩니다.

만약, 전체관측수가 아닌 그룹별 관측수에 따라 정규화된 히스토그램을 그리고 싶다면 stat="density" 옵션과 common_norms=False 옵션을 동시에 사용하면 됩니다. 코드는 다음과 같습니다.

python
# 코드1: 전체관측수로 정규화
sns.displot(penguins, x="flipper_length_mm", hue="species", stat="density")
# 코드2: 그룹별 관측수로 정규화
sns.displot(penguins, x="flipper_length_mm", hue="species", stat="density",
common_norm=False)

이 코드를 실행하면 아래와 같은 그래프가 만들어집니다.

파이썬-데이터-시각화-seaborn-displot-stat-옵션-비교
displot 함수의 stat='density' 옵션과 common_norms=False 옵션 비교 그래프 | Snug Archive

참고로 stat="density"로 정규화한 히스토그램에서는 등급의 간격을 좁힐수록 전체 히스토그램의 모양이 곡선 형태에 가까워집니다. 그래프의 불연속성이 줄어들기 때문이죠. 히스토그램의 모양이 곡선 형태에 가까워진다는 것은 확률밀도함수를 더 정확하게 추정할 수 있게 된다는 것을 뜻합니다.

이처럼 히스토그램은 함수의 형태에 대한 가정(assumptions) 없이 주어진 자료로부터 직접 확률밀도함수를 추정합니다. 이를 비모수적 밀도추정(non-parametric estimation)이라고 합니다. 히스토그램은 비모수적 밀도추정에서 가장 간단히 수행할 수 있는 방법입니다.

지금까지 단변량 히스토그램과 2가지 종류의 정규 히스토그램을 그리는 방법 및 히스토그램에 적용할 수 있는 다양한 옵션을 알아보았습니다. 히스토그램은 직관적입니다. 분포를 한눈에 파악할 수 있고 간편합니다. 그래서 데이터의 분포를 빠르게 알아보고 싶을 때 사용하면 좋습니다.

하지만 한계도 있습니다. 히스토그램으로 확률밀도함수를 추정하면 정확한 결과를 얻기 어렵습니다. 등급의 경계가 계단과 같이 불연속적으로 나타나기 때문입니다. 확률밀도함수는 매끄러운 곡선인데 히스토그램은 울퉁불퉁합니다.

또한, 히스토그램은 등급의 간격과 시작 위치에 따라 모양이 변합니다. 그래프에 대한 해석도 등급을 어떻게 설정하느냐에 따라 달라집니다.

메모리 문제도 있습니다. 데이터의 차원(dimension)이 증가할수록 히스토그램으로 데이터의 분포를 분석하거나 모델을 추정하는데 필요한 표본 데이터의 개수도 기하급수적으로 증가합니다.

이렇게 히스토그램은 단점도 지니고 있습니다. 히스토그램의 단점을 개선한 방법이 있습니다. 바로 커널밀도추정입니다. 지금부터는 커널밀도추정이란 무엇인지, 그리고 Seaborn 라이브러리를 이용해 KDE 함수를 그리는 법을 알아보겠습니다.

5) 커널밀도추정으로 나타낸 확률밀도함수

커널밀도추정이란 커널 함수(kernel function)를 이용해서 확률변수의 확률밀도함수를 추정하는 비모수적 통계 방법입니다. 커널 함수란 원점을 중심으로 대칭을 이루고, 양의(non-negative) 실수(real-valued)값을 갖으며, 적분값이 1인 함수(K) 입니다. 커널 함수로는 대표적으로 가우시안(Gaussian), 코사인(cosine), Epanechnikov 함수 등이 있습니다.

커널-함수-종류
커널 함수 종류 | 위키백과

KDE에서는 데이터를 커널 함수로 대치하여 히스토그램에서 확률밀도함수를 추정할 때 나타났던 불연속성 문제를 해결합니다. KDE로 추정한 확률밀도함수는 부드러운 곡선을 지닙니다.

단, KDE 방법은 극단값이 없는 연속적 자료에 사용합니다. 확률밀도함수는 부드러운 곡선인데 이상치가 있으면 해당 값에서 확률밀도함수가 뾰족한 모양을 띠게 되기 때문입니다. 이상치가 있는 연속적 자료에는 KDE보다는 히스토그램을 사용하는 것이 적합합니다.

KDE방법을 이용해 확률밀도함수를 그리려면 displot 함수에 kind="kde" 옵션을 추가하거나 kdeplot 함수를 이용하면 됩니다. kdeplot을 사용할 때는 'data' 옵션을 사용해서 데이터를 지정해주어야 합니다.

  • displot(data="penguins"): 가능
  • displot(penguins): 가능
  • kdeplot(data="penguins"): 가능
  • kdeplot(penguins): 불가능

여기에 평활량(bandwidth)을 조정하려면 bw_adjust 옵션을 사용하면 됩니다. 이 옵션의 크기에 따라 확률밀도함수의 부드러움(smoothness) 정도가 달라집니다. 코드는 다음과 같습니다.

python
# 코드1
sns.displot(penguins, x="flipper_length_mm", kind="kde")
# 코드2
sns.displot(penguins, x="flipper_length_mm", kind="kde", bw_adjust=.25)
파이썬-데이터-시각화-seaborn-displot-kde-bw_adjust-그래프
displot 함수로 그린 기본 kde 그래프와 평활량을 조정한 kde 그래프 비교 | Snug Archive

히스토그램과 마찬가지로 커널밀도추정에서도 hue 옵션을 사용하면 색으로 구분되는 그룹별 그래프를 그릴 수 있습니다. 사용할 수 있는 옵션은 다음과 같습니다.

  • multiple="stack": 그래프 쌓아서 그리기
  • multiple="fill": 각 값에서 겹친 분포(stacked distribution) 정규화해서 그리기(단변량일 때만 유효, 모든 값에서 y축의 밀도가 1)
  • fill=True: 그래프 불투명하게 그리기
  • common_norm=False: 각 그룹별 관측수로 정규화하기
  • cumulative=True: 누적분포함수 그리기
  • palette: 그래프 색 지정
  • alpha: 그래프 투명도 지정
  • linewidth: 그래프 굵기 지정

palette의 다양한 옵션은 [Seaborn 공식 홈페이지 color palette][]에서 확인하실 수 있습니다.

코드는 다음과 같습니다.

python
# 코드1: 기본 그래프
sns.displot(penguins, x="flipper_length_mm", kind="kde", hue="species")
# 코드2: 그래프 겹쳐서 그리기
sns.displot(penguins, x="flipper_length_mm", kind="kde", hue="species",
multiple="stack")
# 코드3: 모든 값에서 겹친 분포 정규화하기
sns.displot(penguins, x="flipper_length_mm", kind="kde", hue="species",
multiple="fill")
# 코드4: 그래프 불투명하게 그리기
sns.displot(penguins, x="flipper_length_mm", kind="kde", hue="species",
fill=True) # kdeplot에서는 shade=True도 사용 가능
# 코드5: 그룹별 관측수로 각 그룹을 정규화해서 밀도에 대한 누적분포함수 그리기
sns.displot(
penguins, x="flipper_length_mm", kind="kde", hue="species",
cumulative=True, common_norm=False, common_grid=True
)
# 코드6: 각 그룹별 관측수로 정규화해서 확률밀도함수 그리기
sns.displot(
penguins, x="flipper_length_mm", kind="kde", hue="species",
fill=True, common_norm=False, palette="crest",
alpha=.5, linewidth=0
)
파이썬-데이터-시각화-seaborn-displot-kde-그래프
displot 함수의 kde 그래프에 다양한 옵션을 적용해서 그린 그래프 | Snug Archive

연속적 변수가 무한히 커지지 않는 경우에는 cut이라는 매개변수를 사용해 양 끝의 데이터 포인트 범위를 제한하는 것이 좋습니다.

python
sns.displot(tips, x="total_bill", kind="kde") # 코드1
sns.displot(tips, x="total_bill", kind="kde", cut=0) # 코드2
파이썬-데이터-시각화-seaborn-displot-kde-그래프-cut-옵션
displot 함수의 kde 그래프에 cut=0 옵션 비교 그래프 | Snug Archive

만약, 히스토그램과 KDE로 추정한 확률밀도함수를 동시에 그리고 싶다면 displot 함수에 kde=True 옵션을 추가하면 됩니다.

python
sns.displot(diamonds, x="carat", kde=True)
파이썬-데이터-시각화-seaborn-displot-kde-그래프-kde=True-옵션
displot 함수에 kde=True 옵션을 추가해서 그린 그래프 | Snug Archive

6) 경험적 누적분포함수

경험적 누적분포함수(empirical cumulative distribution function, ECDF)는 n개의 데이터 포인트 각각에서 1/n 씩 점프하는 계단 함수입니다. 간단히 줄여 CDF라고도 합니다. ECDF 그래프를 그리려면 displot 함수에 kind="ecdf" 옵션을 주거나 ecdfplot 함수를 사용하면 됩니다. 위에서 사용하지 않은 옵션만 알아보겠습니다.

  • hue_order: # 색 순서 지정
  • complementary=True: 상보 누적분포함수(complementary cumulative distribution function, CCDF) 그리기

상보 누적분포함수는 (1 - CDF)를 의미합니다.

python
# 코드1
sns.displot(penguins, x="flipper_length_mm", kind="ecdf")
# 코드2
sns.displot(penguins, x="flipper_length_mm", kind="ecdf", hue="species")
# 코드3
sns.displot(
data=planets, x="distance", hue="method",
hue_order=["Radial Velocity", "Transit"],
log_scale=True, element="step", fill=False,
cumulative=True, stat="density", common_norm=False,
)
# 코드4: 상보 누적분포함수 그리기(displot으로는 불가능)
sns.ecdfplot(data=penguins, x="bill_length_mm", hue="species", complementary=True)
파이썬-데이터-시각화-seaborn-displot-경험적-누적분포함수
displot와 histplot 함수로 그린 경험적 누적분포함수 | Snug Archive

지금까지 1차원 실수형 데이터를 시각화하는 법을 살펴보았습니다. 이번에는 1차원 범주형 데이터를 시각화하는 법을 알아보겠습니다.

1차원 범주형 데이터 시각화

1차원 범주형 데이터를 시각화할 때는 막대그래프(bar chart)를 가장 자주 사용합니다. Seaborn에서 y축이 범주의 관측수인 막대그래프를 그리려면 countplot 함수를 이용하거나 catplot 함수에 kind="count" 옵션을 주면 됩니다. 여기서는 축 수준 함수인 countplot을 중심으로 알아보겠습니다.

1) 막대그래프

막대그래프의 종류는 다음과 같습니다.

  • 수직 막대그래프(vertical bar graph) = 세로 막대그래프
  • 수평 막대그래프(horizontal bar graph) = 가로 막대그래프
  • 다중 막대그래프(multiple bar chart) = 그룹형 막대그래프(grouped bar graph)
  • 누적 막대그래프(stacked bar graph) = 스택 막대그래프

각 그래프를 차례로 그려보겠습니다.

수직

Seaborn으로 수직 막대그래프를 그리려면 countplot 함수 또는 catplot(kind='count') 함수의 x 매개변수에 데이터를 할당하면 됩니다.

  • color: 막대 색 지정
  • edgecolor: 막대 테두리색 지정
python
# countplot 함수
sns.countplot(x="class", data=titanic) # 코드 1
sns.countplot(x="class", data=titanic, color="skyblue") # 코드2
sns.countplot(x="class", data=titanic, palette="Set3") # 코드3
sns.countplot(x="class", data=titanic, # 코드4
facecolor=(0, 0, 0, 0),
linewidth=5,
edgecolor=sns.color_palette("dark", 3))
# catplot(kind="count") 함수(코드 1과 동일)
sns.catplot(x="class", kind="count", data=titanic)
파이썬-데이터-시각화-Seaborn-수직막대그래프
countplot 함수에 스타일링을 더한 막대그래프 | Snug Archive

수평

Seaborn에서 가로 막대그래프를 만들려면 y 매개변수를 사용하면 됩니다. 코드는 다음과 같습니다.

python
sns.countplot(y="class", data=titanic)
sns.catplot(y="class", kind="count", palette="ch:.25", data=titanic)
파이썬-데이터-시각화-Seaborn-수평막대그래프
Seaborn으로 그린 수평 막대그래프 | Snug Archive

다중

Seaborn으로 다중 막대그래프를 그리려면 hue 옵션을 추가하면 됩니다. 예제 코드는 아래와 같습니다.

python
sns.countplot(y="class", hue="who", data=titanic)
sns.catplot(y="class", hue="who", kind="count", palette="pastel", edgecolor=".6",
data=titanic)
파이썬-데이터-시각화-Seaborn-다중막대그래프
Seaborn으로 그린 다중 막대그래프 | Snug Archive

그룹 막대그래프는 displot 함수에 multiple="dodge" 옵션을 더해서 만들 수도 있습니다.

누적

Seaborn으로 누적 막대그래프를 그리려면 트릭이 필요합니다. barplot 함수로 막대그래프를 겹쳐 그리는 방법이 있습니다. 여기서 각 막대의 y축은 "sepal_length"의 평균과 "petal_length"의 평균을 나타냅니다. ci=None 옵션을 주어 편차를 나타내는 에러바(error bars)를 표시하지 않았습니다.

python
s1 = sns.barplot(x="species", y="sepal_length", color="coral", ci=None, data=iris)
s2 = sns.barplot(x="species", y="petal_length", color="powderblue", ci=None,
data=iris)
파이썬-데이터-시각화-Seaborn-누적막대그래프
Seaborn으로 그린 누적 막대그래프 | Snug Archive

지금까지 파이썬 Seaborn 라이브러리로 1차원 데이터를 시각화하는 법을 알아보았습니다. 다음은 파이썬 데이터 시각화의 두 번째 시간으로 Seaborn을 이용해 2차원 데이터를 시각화하는 법을 알아보겠습니다. 모두 수고 많으셨습니다.

참고 문헌

...

©2022 Snug Archive. All rights reserved.

Contact me at snugarchive@gmail.com.