본문 바로가기
ML & DL/시각화 도구

Seaborn tutorial (2-1) : displot() - histogram

by 별준 2020. 11. 5.

* v0.11.0 기준으로 작성되었습니다.

 

이번에는 seaborn의 데이터 분포 시각화에 대해서 알아보도록 하겠습니다.

 

- Visualizing distributions of data

데이터의 분포를 시각화하기 위한 API는 다양합니다. 

이전 게시글에서 언급했듯이 figure-level function과 axes-level function이 있는데, displot()은 figure-level이고, histplot(), kdeplot(), ecdfplot(), rugplot()은 axes-level입니다.

 

relplot()과 마찬가지로, displot() 또한 'kind' 매개변수를 통해서 axes-level function들과 결합해서 그래프를 그리게 됩니다. kind 매개변수를 지정하지 않으면 기본으로 'hist'가 되며, 히스토그램이 기본으로 그려지게 됩니다.

 

자세한 API 정보는 아래 공식홈페이지를 참조바랍니다.

displot([data, x, y, hue, row, col, …])

Figure-level interface for drawing distribution plots onto a FacetGrid.

histplot([data, x, y, hue, weights, stat, …])

Plot univariate or bivariate histograms to show distributions of datasets.

kdeplot([x, y, shade, vertical, kernel, bw, …])

Plot univariate or bivariate distributions using kernel density estimation.

ecdfplot([data, x, y, hue, weights, stat, …])

Plot empirical cumulative distribution functions.

rugplot([x, height, axis, ax, data, y, hue, …])

Plot marginal distributions by drawing ticks along the x and y axes.

distplot([a, bins, hist, kde, rug, fit, …])

DEPRECATED: Flexibly plot a univariate distribution of observations.

 

이번 글에서는 히스토그램(histogram)으로 시각화하는 방법에 대해서 알아보도록 하겠습니다.

 

먼저 필요한 라이브러리들을 import하고, 사용할 dataset을 불러오겠습니다. 펭귄에 대한 정보이며, 부리 길이, 날개 길이 등의 정보가 있습니다. 그리고 set_theme 메소드를 사용했는데, darkgrid로 설정되는 것이 개인적으로 시각적으로 더 효과적으로 느껴지는 것 같습니다.

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme()

penguins = sns.load_dataset("penguins")
penguins.head()

 

sns.displot(penguins, x="flipper_length_mm")

기본적으로 histogram을 그리는 방법입니다. relplot()을 사용할 때와는 다르게 data매개변수를 키워드로 지정하지 않고, 바로 penguins 데이터를 넣어주었습니다. 이것은 displot의 data 매개변수가 위치로 전달될 수도 있고, 키워드를 통해서도 전달될 수 있기 때문입니다. 당연히 data=penguins로 해주어도 정상적으로 동작합니다. 다만, 키워드를 사용하지 않는다면 파라미터 중에서 제일 먼저 입력되어야 합니다.

 

x에 대해서 count를 하기 위해서 x 파라미터에만 변수를 지정해주었는데, 반대로 y 파라미터에만 변수를 지정할 수도 있습니다. 이렇게 한다면, 옆으로 누운 히스토그램이 그려지게 됩니다.

sns.displot(penguins, y="flipper_length_mm")

x, y를 모두 지정해주는 경우는 튜토리얼 진행하면서 알아보도록 하겠습니다.

 

막대그래프 크기 선택

distplot()과 histplot()은 binwidth 파라미터를 통해서 막대그래프의 크기를 조절할 수 있습니다. 위의 그래프는 bin의 크기가 크기 때문에, 세부적인 정보들을 감추고 있습니다.(큰 범위로 count함) 따라서, bin의 크기를 조금 더 작게 지정해준다면, 더 많은 정보를 그래프에 표시할 수 있습니다. 

sns.displot(penguins, x="flipper_length_mm", binwidth=3)

또는, 막대의 개수를 지정할 수도 있습니다. 개수에 맞추어서 막대의 너비가 결정됩니다.

sns.displot(penguins, x="flipper_length_mm", bins=20)

만약 변수의 label이 많지 않은데 막대의 크기나 개수를 지정하지 않는다면, 그래프가 보기 좋게 그려지지 않을 수가 있습니다. 아래 tips dataset의 size는 categorical data입니다.(1, 2, 3, 4, 5, 6)

tips = sns.load_dataset("tips")
sns.displot(tips, x="size")

몇 가지 방법이 있지만, 제가 생각하기에는 아래 방법이 가장 사용하기 편하다고 느껴집니다. 막대의 크기도 조정해주면서, 위에서는 연속적인 데이터 분포를 막대그래프로 보여주고 있다면, 'discrete' 파라미터를 사용해서 이산분포를 그려줄 수 있습니다.

sns.displot(tips, x="size", discrete=True)

이산분포형을 가지는 데이터는 위와 같이 x축을 기준으로 각 데이터가 딱 붙어서 표시되는데, 'shrink' 파라미터를 사용하면, 막대의 너비를 조절할 수 있습니다.(discrete를 True로 설정하면, binwidth로 너비조절이 안됩니다.)

sns.displot(tips, x="day", shrink=.8)

위와 같이 막대들의 너비가 0.8만큼 너비 비율이 감소하는 것을 볼 수 있으며, 기본비율인 1은 다닥다닥 붙어있는 막대그래프입니다.

 

다른 변수를 추가해서 시각화하기

'hue' 파라미터를 사용하면, 새로운 데이터 변수를 추가해서 색상으로 구분되는 그래프를 그릴 수 있습니다. 예제를 통해서 살펴보도록 하죠.

아래 코드에서는 펭귄 날개 길이를 살펴보는 그래프에서 종의 정보를 추가했습니다.

sns.displot(penguins, x="flipper_length_mm", hue="species")

기본적으로 서로 다른 히스토그램은 겹쳐져서 나타나게 됩니다. 그래서, 위 그래프를 보시면 구분이 어려울 것입니다. 조금 더 구분이 쉽도록 하기 위해서 위와 같은 bar plot을 'step' plot으로 변경할 수 있습니다. 'element' 파라미터를 사용하면 되는데, 이 파라미터를 지정하지 않으면 기본값은 'bars'로 들어가서 위와 같은 히스토그램이 그려지게 됩니다.

sns.displot(penguins, x="flipper_length_mm", hue="species", element="step")

또는, 'multiple' 파라미터를 설정해서 쌓아올리는 것처럼 그래프를 그릴 수 있습니다. 위에서 구분되지 않았던 경우에는 'multiple' 파라미터가 기본값으로 'layer'로 설정되어 있기 때문입니다. 'stack'으로 설정하게 되면, 히스토그램이 겹쳐지지 않게 됩니다.

sns.displot(penguins, x="flipper_length_mm", hue="species", multiple="stack")

stack 히스토그램은 변수들간의 비율 정도를 강조할 수 있지만, 분포를 확인하기에 어려운 부분이 있습니다. 이런 경우에는 "dodge" bar를 사용해서 각각의 막대로 나타낼 수 있지만, 범주(category)가 적은 경우에만 사용하는 것을 추천합니다. 막대의 너비는 자동으로 조절됩니다.

sns.displot(penguins, x="flipper_length_mm", hue="species", multiple="dodge")

이것도 조금 보기 불편하다면, relplot()과 마찬가지로 displot()도 FacetGrid 기반으로 그려지기 때문에, 'col' 파라미터를 사용해서 각각의 그래프로 쉽게 나누어서 나타낼 수 있습니다.

sns.displot(penguins, x="flipper_length_mm", col="species")

 

추가로, 현재 y축은 Count로 설정되어 있는데, 'stat' 파라미터를 통해서 y축을 정규화(normalization)해서 나타낼 수도 있습니다.

위는 hisplot() API에 있는 stat 파라미터의 내용입니다. 지정하지 않으면 기본값으로 'count'로 설정되며, 'frequency' / 'density' / 'propability'로 변경가능합니다.

sns.displot(penguins, x="flipper_length_mm", hue="species", stat="density", element="step")

기본적으로 전체 분포에 대해서 정규화가 적용되는데, 'common_norm' 파라미터를 해제해서 각 subset들을 독립적으로 정규화할 수 있습니다.

sns.displot(penguins, x="flipper_length_mm", hue="species", stat="density", element="step", common_norm=False)

두 개의 데이터 분포 시각화

지금까지 그래프를 그릴 때, 'x'나 'y' 파라미터를 하나만 사용해서 단일 변수에 대한 분포를 나타내거나 'hue' 파라미터를 사용해서 두 번째 데이터를 조건부로 나타냈지만, 'x', 'y' 변수를 동시에 사용이 가능합니다. 

sns.displot(penguins, x="bill_length_mm", y="bill_depth_mm", cbar=True)

histogram에서는 위와 같이 나타나게 되며, 직사각형 내에 데이터 카운트를 색상으로 표시합니다. 나중에 보게 되겠지만, heatmap()과 유사하며, 진할수록 데이터의 수가 많다는 것을 의미합니다. 참고로, 'cbar' 파라미터를 설정하지 않으면 오른쪽 bar가 나타나지 않습니다.

 

두 개의 변수를 쓰는 경우에도 'hue' 매개변수를 사용해서 조건부 그래프로 나타낼 수 있습니다.

sns.displot(penguins, x="bill_length_mm", y="bill_depth_mm", hue="species")

그리고, 하나의 변수를 사용했을 때처럼 'binwidth' 매개변수를 통해 bin size나 bandwidth의 선택으로 두 변수 분포를 조절해서 나타낼 수 있습니다. 다만, 한 쌍의 값을 전달하여 각 변수에 대해서 튜닝할 수 있습니다.

sns.displot(penguins, x="bill_length_mm", y="bill_depth_mm", binwidth=(2, .5))

이렇게 두 개의 데이터를 사용할 때, 이 데이터들은 모두 이산형의 데이터로도 가능하며, 하나는 이산형, 하나는 연속형도 가능합니다. 이번에는 diamonds dataset을 사용해서 살펴보겠습니다.

diamonds = sns.load_dataset("diamonds")
sns.displot(diamonds, x="price", y="clarity", log_scale=(True, False))

위 그래프처럼, 'log_scale' 매개변수를 통해 변수 x는 로그 스케일을 적용할 수도 있습니다.

 

아래는 x, y 변수에 모두 이산형 데이터를 사용한 경우의 그래프입니다.

sns.displot(diamonds, x="color", y="clarity")

 

 

여기까지 displot() / histplot()의 기본적인 사용법을 알아보았고, 다음 게시글에서 이어서 Kernel density estimation / kdeplot()에 대해서 알아보도록 하겠습니다.

댓글