본문 바로가기
데이터분석/시각화

[파이썬 데이터 분석] 시각화, pyplot과 seaborn 라이브러리 튜토리얼 - 2

by CodingKwon 2021. 6. 21.

파이썬 데이터 분석

pyplot과 seaborn 라이브러리 튜토리얼 - 2


이 주피터노트북은 Seaborn에 대한 전반적인 설명을 담고 있습니다.


1. Seaborn이란?

  • Seaborn은 Matplotlib을 기반으로 다양한 색상 테마와 통계용 차트 등의 기능을 추가한 시각화 패키지입니다.
  • 기본적인 시각화 기능은 Matplotlib 패키지에 의존하며 통계 기능은 Statsmodels 패키지에 의존합니다.

2. 통계적 관계 시각화

  • Seaborn은 복잡한 데이터 세트 구조를 표현할 수있는 간단하고 이해하기 쉬운 데이터 표현을 사용하기 때문에 상당히 밝을 수 있습니다.
  • 색조, 크기 및 스타일의 의미를 사용하여 최대 3개의 추가 변수를 매핑하여 향상시킬 수있는 2차원 그래픽을 플로팅하기 때문에 그렇게 할 수 있습니다.
  • Seaborn의 대표적 3가지 함수
    • relplot()
    • scatterplot()
    • lineplot()
다음은 import seaborn으로 seaborn을 불러오고 sns라는 별칭을 붙여주는 방법입니다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns # seaborn 불러오기 (별칭 plt)
sns.set_theme(style="darkgrid")

3. 산점도와 변수 연결

  • 산점도는 통계 시각화의 중심입니다.
  • 점 구름을 사용하여 두 변수의 공동 분포를 묘사하며, 여기서 각 점은 데이터 세트의 관찰을 나타냅니다.
  • 이 묘사를 통해 눈은 그들 사이에 의미있는 관계가 있는지에 대한 상당한 양의 정보를 추론 할 수 있습니다.
  • 산점도를 그리는 방법
    • 기본적으로 relplot()을 사용합니다.
    • kind의 default는 scatter입니다.
다음은 tips라는 데이터셋을 불러와서 산점도를 표현한 예시입니다.

3-1. 산점도 hue semantic

  • 서로 다른 차원의 데이터를 플롯에 추가하였을 때 구별을 위해 hue(색조) 값으로 구별할 수 있습니다.
다음은 tips 데이터셋을 hue에 "smoker"로 두 데이터를 구별하는 예시입니다.
tips = sns.load_dataset("tips") # sns에 tips 데이터 불러오기
sns.relplot(x="total_bill", y="tip", data=tips); # 산점도로 표현

3-2. 산점도 style

  • 서로 다른 차원의 데이터를 플롯에 추가하였을 때 구별을 위해 style에 구별을 줄 수도 있습니다.
다음은 style을 통해서 smoker를 구별하는 예시입니다.
sns.relplot(x="total_bill", y="tip", hue="smoker", style="smoker",
            data=tips);

3-3. 산점도 hue, style 사용

  • 각 포인트의 색조와 스타일을 개별적으로 변경하여 여러 개의 변수를 표현할 수도 있습니다.
다음은 색조와 스타일을 개별적으로 적용하여 흡연여부와 시간여부로 팁을 구별하는 예시입니다.
- 흡연 여부 : 파랑, 주황
- 시간(점심, 저녁) : 동그라미, 네모
sns.relplot(x="total_bill", y="tip", hue="smoker", style="time", data=tips);

3-4. 산점도의 hue(색조)의 의미를 순차적 색상 팔레트로 나타내기

  • hue의 값이 범주형 범위가 아닌 순차적인 색상으로도 팔레트를 표현할 수 있습니다.
  • hue의 값이 숫자형일 경우 자동으로 적용됩니다. (float으로 적용)
다음은 산점도를 숫자 범위로 나타낸 예시입니다.
sns.relplot(x="total_bill", y="tip", hue="size", data=tips);

3-5. 산점도 palette 세부설정

  • 사용자 정의 된 cubehelix 색상 팔레트를 사용할 수 있습니다.
  • cubehelix 문서
다음은 palette="ch:r=-.5,l=.75" 설정을 주어서 palette를 직접 지정하는 예시입니다.
sns.relplot(x="total_bill", y="tip", hue="size", palette="ch:r=-.5,l=.75", data=tips);

3-6. 산점도 크기 설정

  • size 매개변수를 통해서 사이즈를 설정할 수 있습니다.
다음은 size를 다르게 주어 산점도를 나타내는 예시입니다.
sns.relplot(x="total_bill", y="tip", size="size", data=tips);

  • 산점도의 크기를 사용자 지정할 수도 있습니다.
다음은 sizes=(15, 200)으로 크기를 15~200으로 지정하는 예시입니다.
sns.relplot(x="total_bill", y="tip", size="size", sizes=(15, 200), data=tips);

4. 라인 플롯으로 연속성 강조

  • 일부 데이터 세트의 경우 한 변수의 변화를 시간 함수 또는 유사한 연속 변수로 사용될 수 있습니다.
  • lineplot()은 선 그림을 그리는 것입니다.
    • seaborn에서 relplot함수에 kind="line"를 지정하면 lineplot()을 사용할 수 있습니다.
df = pd.DataFrame(dict(time=np.arange(500),
                       value=np.random.randn(500).cumsum()))
g = sns.relplot(x="time", y="value", kind="line", data=df) # kind="line"을 주어 lineplot()을 사용합니다.
g.fig.autofmt_xdate()

4-1. 라인 플롯으로 집계 및 불확실성 표현

  • 라인 플롯은 집계나 불확실성을 시각화하기에 좋은 방식입니다.
  • seaborn의 기본 동작 x은 평균과 평균 주위에 95% 신뢰 구간을 플로팅하여 각 값 에서 여러 측정 값 을 집계 하는 것입니다.
다음은 fmri 데이터 셋을 불러와서 kind="line" 방식으로 표현한 예시입니다.
fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", kind="line", data=fmri); # line으로 플롯

  • 신뢰 구간은 부트 스트랩을 사용하여 계산되며, 이는 대규모 데이터 세트의 경우 시간이 많이 소요될 수 있습니다.
  • 따라서 비활성화 할 수 있습니다.
다음은 cl=None으로 신뢰 구간을 비활성화 한 예시입니다.
sns.relplot(x="timepoint", y="signal", ci=None, kind="line", data=fmri);

  • 신뢰 구간 대신 표준 편차를 플로팅하여 각 시점에서 분포의 산포를 나타내는 방식도 가능합니다.
다음은 cl="sd"으로 신뢰 구간을 표준 편차로 나타내는 예시입니다.
sns.relplot(x="timepoint", y="signal", kind="line", ci="sd", data=fmri);

  • 데이터에 각 지점에서 여러 관측치가 있는 경우 estimator 매개 변수를 None으로 설정하면 이상한 효과가 발생할 수 있습니다.
다음은 estimator=None으로 설정한 예시입니다.
sns.relplot(x="timepoint", y="signal", estimator=None, kind="line", data=fmri);

5. 시맨틱 매핑을 사용하여 데이터의 하위 집합 플로팅

  • 시맨틱 매핑을 사용 lineplot()하면 데이터가 집계되는 방식도 결정됩니다.
  • 예를 들어, 두 수준의 색조 의미 체계를 추가하면 플롯이 두 개의 선과 오류 대역으로 분할되고, 각각에 해당하는 데이터의 하위 집합을 나타내기 위해 색상이 지정됩니다.
다음은 event를 hue로 구별하여 나타낸 예시입니다.
sns.relplot(x="timepoint", y="signal", hue="event", kind="line", data=fmri);

  • 선 플롯에 스타일 의미를 추가하면 기본적으로 선의 대시 패턴이 변경됩니다.
다음은 hue="region"과 style="event"로 개별적으로 플롯을 나타내는 예시입니다.
sns.relplot(x="timepoint", y="signal", hue="region", style="event",
            kind="line", data=fmri);

  • 대시와 함께 각 관찰에 사용 된 마커로 하위 집합을 식별 할 수 있습니다.
다음은 마커를 통해서 플롯들을 구별하는 예시입니다.
sns.relplot(x="timepoint", y="signal", hue="region", style="event",
            dashes=False, markers=True, kind="line", data=fmri);

  • 산점도와 마찬가지로 여러 의미를 사용하여 선 플롯을 만들 때주의해야합니다.
  • 때로는 정보를 제공하지만 구문 분석 및 해석이 어려울 수도 있습니다.
  • 그러나 하나의 추가 변수에 대한 변경 사항만 검사하는 경우에도 선의 색상과 스타일을 모두 변경하는 것이 유용 할 수 있습니다.
  • 이렇게하면 흑백으로 인쇄하거나 색맹이있는 사람이 볼 때 플롯에 더 쉽게 액세스 할 수 있습니다.
다음은 두 개의 플롯을 각각 hue와 style을 모두 변경하는 예시입니다.
sns.relplot(x="timepoint", y="signal", hue="event", style="event",
            kind="line", data=fmri);

5-1. 반복 측정 데이터로 작업하는 경우

  • 여러 번 샘플링 된 단위가있는 경우 의미를 통해 구분하지 않고 각 샘플링 단위를 개별적으로 플로팅 할 수도 있습니다.
다음은 estimator를 None으로 주고, data=fmri.query("event == 'stim'")를 설정하여
각 샘플링 단위로 개별적 플로팅을 한 예시입니다.
sns.relplot(x="timepoint", y="signal", hue="region",
            units="subject", estimator=None,
            kind="line", data=fmri.query("event == 'stim'"));

5-2. 기본 컬러맵 및 범례 처리

  • lineplot()는 hue(색조) 의미 체계가 범주 형인지 숫자인지에 따라 달라집니다.
다음은 coherence는 숫자형, choice는 범주형으로 플롯을 나타내는 예시입니다.
dots = sns.load_dataset("dots").query("align == 'dots'")
sns.relplot(x="time", y="firing_rate",
            hue="coherence", style="choice",
            kind="line", data=dots);

  • hue변수를 목록 또는 사전으로 전달하여 각 줄에 특정 색상 값을 제공 할 수 있습니다.
다음은 sns.cubehelix_palette(light=.8, n_colors=6)처럼 hue변수를 등록하여 사용하는 방식의 예시입니다.
palette = sns.cubehelix_palette(light=.8, n_colors=6)
sns.relplot(x="time", y="firing_rate",
            hue="coherence", style="choice",
            palette=palette,
            kind="line", data=dots);

  • 컬러맵을 정규화되는 방식으로도 사용할 수 있습니다.
다음은 hue_norm=LogNorm()을 사용하여 컬러맵의 정규화 방식으로 사용합니다.
from matplotlib.colors import LogNorm을 사전에 추가해야 사용가능합니다.
from matplotlib.colors import LogNorm
palette = sns.cubehelix_palette(light=.7, n_colors=6)
sns.relplot(x="time", y="firing_rate",
            hue="coherence", style="choice",
            hue_norm=LogNorm(),
            kind="line",
            data=dots.query("coherence > 0"));

5-3. 선의 너비를 변경

  • 선의 너비를 통해서도 구별할 수 있습니다.
  • size 매개변수를 이용합니다.
다음은 size="coherence"를 주어 선의 너비로 coherence를 구별합니다.
sns.relplot(x="time", y="firing_rate",
            size="coherence", style="choice",
            kind="line", data=dots);

  • size는 보통 수치형이겠지만 범주형으로도 사용가능합니다.
다음은 범주형을 size로 설정하여 나타낸 예시입니다.
sns.relplot(x="time", y="firing_rate",
           hue="coherence", size="choice",
           palette=palette,
           kind="line", data=dots);

6. 날짜 데이터로 플로팅하기

  • 선 그림은 실제 날짜 및 시간과 관련된 데이터를 시각화하는 데 자주 사용됩니다.
  • matplotlib의 날짜 형식을 눈금 레이블로 지정하는 기능을 활용할 수 있습니다.
다음은 날짜를 플로팅하여 나타낸 예시입니다.
%Y-%m-%d 형식을 사용했습니다.
df = pd.DataFrame(dict(time=pd.date_range("2017-1-1", periods=500),
                       value=np.random.randn(500).cumsum()))
g = sns.relplot(x="time", y="value", kind="line", data=df)
g.fig.autofmt_xdate()

7. 패싯(facets)이 있는 여러 관계 표시

  • 함수가 여러 의미 변수를 한 번에 표시 할 수 있지만 항상 효과적인 것은 아닙니다.
  • 이런 상황에서 두 변수 간의 관계가 하나 이상의 다른 변수에 어떻게 의존하는지 이해하고 싶을 때 사용하는 방식입니다.
  • 가장 좋은 방법은 하나 이상의 플롯을 만드는 것입니다.
  • 즉, 여러 축을 만들고 각 축에 데이터의 하위 집합을 플로팅합니다.
다음은 tips 데이터를 Lunch와 Dinner로 두 개의 플롯을 나누어 흡연자 여부에 따른 팁을 보여주는 예시입니다.
sns.relplot(x="total_bill", y="tip", hue="smoker",
            col="time", data=tips); # col을 사용하여 두 개의 플롯으로 나눔

  • 이 방식을 이용한다면 더 많은 두 변수의 영향을 나타낼 수 있습니다.
    • col : 열에 대한 패싯(facet)
    • row : 행에 대한 패싯(facet)
  • FacetGrid는 각 패싯 의 높이와 가로 세로 비율로 매개 변수화됩니다.
다음은 열은 region, 행은 event로 나누고 각 플롯의 크기는 height=3으로 설정한 예시입니다.
sns.relplot(x="timepoint", y="signal", hue="subject",
            col="region", row="event", height=3,
            kind="line", estimator=None, data=fmri); # col, row, height를 설정하여 4개의 플롯으로 나타냄

  • 변수의 여러 수준에서 효과를 조사하려는 경우 해당 변수를 열에서 패싯 처리 한 다음 패싯을 행으로 "래핑"하는 것이 좋습니다.
다음은 col_wrap=5로 래핑한 결과에 대한 예시입니다.
sns.relplot(x="timepoint", y="signal", hue="event", style="event",
            col="subject", col_wrap=5, # col_wrap 사용
            height=3, aspect=.75, linewidth=2.5,
            kind="line", data=fmri.query("region == 'frontal'"));

댓글