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

Seaborn tutorial (1-2) : relplot() - line plot

by 별준 2020. 11. 4.

2020/11/04 - [ML and DL] - Seaborn tutorial (1-1) : relplot() - scatter plot

지난 글에 이어서 relplot()에서 line plot을 그리는 기본적인 방법과 여러개의 plot을 한번에 나타내는 방법을 살펴보도록 하겠습니다.

 

2. line plots

시간과 같은 연속된 값을 가진 변수들에 대해서 시각화가 필요할 때, line plot을 사용하는 것이 편리하며, lineplot()을 사용해서 line plot을 그릴 수 있습니다. scatterplot()과 마찬가지로 relplot()으로 사용가능하며, kind="line"을 사용해서 line plot을 적용할 수 있습니다.

 

먼저 line plot을 위한 dataset을 생성해보겠습니다. 0초에서 500초의 값의 분포입니다.

df = pd.DataFrame(dict(time=np.arange(500), 
                       value=np.random.randn(500).cumsum()))
df.head()

x축은 time이고, y축은 value입니다. 그리고 line plot을 위해서 kind="line" 매개변수를 추가했습니다. autofmt_xdata() 메소드는 matplotlib의 메소드입니다.

g = sns.relplot(x="time", y="value", kind="line", data=df)
g.fig.autofmt_xdate()

lineplot()은 기본적으로 그래프를 그리기 전에 x값을 기준으로 데이터를 정렬하고 그래프를 그립니다. 따라서, x가 정렬되지 않은 데이터를 가지고 그래프를 그리면 어떻게 되는지 한번 확인해보겠습니다.

df = pd.DataFrame(np.random.randn(500, 2).cumsum(axis=0), columns=["x", "y"])
df.head()

sns.relplot(x="x", y="y", kind="line", data=df)

이렇게 x가 순차적이지 않음에도 불구하고, line이 정렬된 x의 값들로 이어져있는 것을 볼 수 있습니다. 

sort=False 매개변수로 정렬을 적용하지 않을 수 있는데, 정렬을 적용하지 않으면 정렬되지 않은 x의 값을 순차적으로 이어버리게 됩니다.

sns.relplot(x="x", y="y", sort=False, kind="line", data=df)

 

더 복잡한 dataset은 하나의 x 변수에 대해서 여러 개의 측정값 y를 가질 수 있습니다. 이러한 dataset인 경우에 seaborn의 기본 동작은 각 x의 측정값들에 대해서 평균과 95%의 신뢰구간을 평균 주위에 표시하게 됩니다.

새로운 데이터를 가지고 그래프를 그려보도록 하겠습니다.

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

sns.relplot(x="timepoint", y="signal", kind="line", data=fmri)

이렇게 표시되는 신뢰구간은 bootstrapping을 사용해서 계산되며, 아래와 같은 방법으로 disable할 수 있습니다.(ci=None)

sns.relplot(x="timepoint", y="signal", kind="line", ci=None, data=fmri)

그리고 신뢰구간을 표시하는 것 대신, 표준편차를 표시하여 각 시점 x에서의 분포를 나타낼 수도 있습니다.(ci="sd")

sns.relplot(x="timepoint", y="signal", kind="line", ci="sd", data=fmri)

위와 같이 표시하지 않고, 모든 값들을 표시하려면(aggregation을 disable), estimator 파라미터를 None으로 설정하면 됩니다. 하지만, 각 지점에서 여러 개의 측정값을 가지고 있다면 이상하게 표시될 수 있습니다.

sns.relplot(x="timepoint", y="signal", estimator=None, kind="line", data=fmri) 

 

lineplot() 함수는 scatterplot()과 동일하게 hue, size, style 등의 파라미터를 사용할 수 있고, 이 API는 scatterplot()과 동일합니다. 

hue 파라미터를 추가하면, 두 개의 선과 신뢰구간을 각각 대응되는 색으로 나타내게 됩니다.

sns.relplot(x="timepoint", y="signal", hue="event", kind="line", data=fmri)

그리고, style 매개변수를 추가하면, scatter plot에 마커에 대응되는 다양한 선의 style을 사용해서 나타낼 수 있습니다.

sns.relplot(x="timepoint", y="signal", hue="region", style="event", kind="line", data=fmri)

그리고 각 subset의 관측치에 마커를 적용해서 더 보기 편하게 나타낼 수도 있습니다.

dashes 파라미터로 line의 dash를 해제하고, markers 파라미터의 값을 True로 적용하였습니다.

sns.relplot(x="timepoint", y="signal", hue="region", style="event", dashes=False, markers=True, kind="line", data=fmri)

만약 두 개의 line을 비교하려면, hue와 style만 적용해서 비교하는 것이 편리하고, 시각적으로도 잘 비교가 됩니다.

sns.relplot(x="timepoint", y="signal", hue="event", style="event", kind="line", data=fmri)

lineplot()의 기본 colormap과 legend의 핸들링은 hue 매개변수가 categorical이냐 numeric이냐에 따라 다릅니다.

dots = sns.load_dataset("dots").query("align=='dots'")
dots.head()

새로운 dataset을 불러오고, hue에 numeric인 coherence 데이터를 적용해보았습니다.

sns.relplot(x="time", y="firing_rate",
            hue="coherence", style="choice",
            kind = "line", data=dots)

위와 같이 hue 매개변수가 numeric임에도 불구하고, linear color scale이 아닌 log scale로 색이 분포되어서, 구별하기 힘들게 그래프가 나타날 수 있습니다. 이 경우에는 list 또는 dictionary로 각 line에 대한 특정 색상값을 적용할 수 있습니다.

palette = sns.cubehelix_palette(light=.8, n_colors=6)
palette

위와 같은 palette를 생성해서, 그래프에 적용해주면 됩니다.

sns.relplot(x="time", y="firing_rate",
           hue="coherence", style="choice",
           palette=palette,
           kind="line", data=dots)

 

size 파라미터는 line의 두께를 설정할 수 있습니다.

sns.relplot(x="time", y="firing_rate",
            size="coherence", style="choice",
            kind="line", data=dots)

날짜/시간 관련 데이터 시각화

Line plots는 종종 실제 날짜나 시간과 관련된 데이터를 시각화하는데 유용하게 사용될 수 있습니다.

df = pd.DataFrame(dict(time=pd.date_range("2017-1-1", periods=500),
                       value=np.random.randn(500).cumsum()))
df.head()

g = sns.relplot(x="time", y="value", kind="line", data=df)
g.fig.autofmt_xdate()

 

3. Showing multiple relationships with facets

다양한 semantic variables를 하나의 그래프에 한번에 표시했지만, 시각적으로 효과적이지 않을 수도 있으며, 따라서, 두 개 이상의 그래프가 필요할 때가 있습니다. relplot()은 FacetGrid 기반이기 때문에 쉽게 하나 이상의 그래프를 나타낼 수 있습니다. 이전 게시글에서 사용했던 tips, fmri dataset을 사용해서 살펴보도록 하겠습니다.

 

sns.relplot(x="total_bill", y="tip", hue="smoker",
            col="time", data=tips)

col 매개변수를 사용해서 그래프를 추가하였습니다. 

만약 두 개의 변수의 영향성을 평가하려면, rows를 추가해서 나타낼 수 있습니다.(row 매개변수 추가)

sns.relplot(x="timepoint", y="signal", hue="subject",
            col="region", row="event", height=3,
            kind="line", estimator=None, data=fmri)

위 그래프의 경우에 subject 카테고리가 너무 많아서 그래프를 효과적으로 분석하기가 힘들고, col 매개변수에 subject를 대입해서 사용하면 되는데, subject의 카테고리가 많기 때문에, col_wrap 매개변수를 사용해서 한 줄에 몇 개의 그래프를 그리도록 설정할 수 있습니다.

sns.relplot(x="timepoint", y="signal", hue="event", style="event",
            col="subject", col_wrap=5,
            height=3, aspect=.75, linewidth=2.5,
            kind="line", data=fmri.query("region == 'frontal'"))

 

추가적으로 height는 그래프의 높이를 지정할 수 있습니다. 그래프의 너비는 그래프의 높이를 설정해주면, 그래프 비율에 맞춰서 자동으로 설정됩니다. 이때, 이 비율은 aspect 매개변수로 설정할 수 있습니다. 따라서, 너비는 aspect * height로 설정됩니다. linewidth는 그래프 line의 굵기를 설정합니다.

 

 

두 게시글에 걸쳐서 relplot()의 기능을 간단하게 살펴보았습니다. 모든 파라미터에 대해서 알아보려고 했지만, 게시글이 너무 길어지고, 개인적으로 이정도만 알아도 충분하다고 생각이 듭니다. 다음에 더 필요하다고 생각이 들면, 다시 정리를 해보도록 하겠습니다.

댓글