본문 바로가기

부스트캠프 AI Tech 공부 기록/Data Visualization

[Data Viz] Matplotlib 사용법 : Scatter Plot

Data Visualization

2-4. Scatter Plot

1) Scatter Plot이란?

Scatter Plot 

- 점을 사용하여 두 feature간의 관계를 알기 위해 사용하는 그래프

- 산점도 등의 이름으로 사용됨

- 직교 좌표계에서 x축/y축에 feature값을 매핑하여 사용

- .scatter()를 이용해서 구현

Scatter Plot의 요소

- 점에 대해 다양한 variation을 사용할 수 있다.

  • 색(color)
  • 모양(marker)
  • 크기(size)

Scatter Plot의 목적

- scatter plot은 상관관계를 확인하기 위해 그린다.

  • 양의 상관관계인지
  • 음의 상관관계인지
  • 상관관계가 없는지

- scatter plot에서는 세 가지를 확인하자

  • 군집(cluster) : 점들이 특정 그룹으로 모여있는지
  • 값 사이의 차이(gap in values) : 점들 간의 값에 차이가 존재하는지
  • 이상치(outliers) : 점들이 모여있는 군집을 크게 벗어난 이상치의 점들이 존재하는지

 

2) 기본 Scatter Plot 그리기

기본 Scatter Plot 그리기

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111, aspect=1)

np.random.seed(970725)

x = np.random.rand(20)
y = np.random.rand(20)

ax.scatter(x, y) 	# scatter plot 그리기
ax.set_xlim(0, 1.05)
ax.set_ylim(0, 1.05)

plt.show()

 

Scatter Plot의 요소 변경하기

- 색 : color 파라미터로 변경

- 모양 : marker 파라미터로 변경 

- 크기 : size(또는 s) 파라미터로 변경

fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111, aspect=1)

np.random.seed(970725)

x = np.random.rand(20)
y = np.random.rand(20)
s = np.arange(20) * 20

ax.scatter(x, y, 
           s= s, 		# 점의 크기
           c='skyblue',		# 점의 색깔
           marker='o',		# 점의 모양
           linewidth=2,		# 점의 테두리 두께
           edgecolor='blue') 	# 점의 테두리 색깔

plt.show()

 

 

3)  Scatter Plot Tips

정확한 Scatter Plot 그리기

- Overplotting 문제 : 점의 개수가 많아질수록 분포를 파악하기 힘들어진다.

- 해결 방법

  • 투명도 조정
  • jittering : 점의 위치를 약간씩 변경(다른 방식들이 더 좋기 때문에 추천하지 않는다)
  • 2차원 히스토그램 : 히트맵을 사용하여 깔끔하게 시각화
  • contour plot : 분포를 등고선을 사용하여 표현

점의 요소와 인지

- 점의 요소를 통해 특정 점을 강조하거나 점들을 구분할 수 있다

- 색

  • 점의 색을 다르게 하여 구별
  • 연속적인 데이터는 그레디언트로, 이산적인 데이터는 개별 색상으로 표현

- 마커

  • 세모, 동그라미 등 점의 모양 변경
  • 점의 모양을 다르게 하는 방식은 거의 구별하기 힘들고 크기가 고르지 않으면 잉크 비례 원칙을 위배하기 때문에 지양한다(색이나 크기와 함께 쓰는 것도 방법이다)

- 크기 

  • 점의 크기들을 다르게 하여 구별
  • 흔히 bubble chart라고 부름
  • 구별하기는 쉽지만 오용하기 쉽고 잉크 비례의 원칙을 따르지 않을 수 있음
  • 관계보다는 각 점간 비율에 초점을 두는 경우 사용 가능
  • SWOT분석에 활용 가능

 

인과관계와 상관관계

- 인과관계(causal relation)와 상관관계(correlation)는 다르다

- 인과관계는 항상 사전 정보와 함께 가정으로 제시해야 한다

- 상관관계는 heatmap과 연관이 있다

 

추세선

- scatter plot에서 추세선을 사용하면 scatter의 패턴을 유추할 수 있다

- 단, 추세선이 두 개 이상이 되면 가독성이 떨어지므로 주의해야 한다

 

ETC

- Grid는 점과 겹칠 수 있기 때문에 지양하도록하고 사용한다면 최소한으로, 색은 무채색으로 하자

- 범주형이 포함된 관계에서는 heatmap이나 bubble chart를 추천한다

 

실제 데이터로 살펴보기

- 데이터셋 준비 : 붓꽃 데이터셋

iris = pd.read_csv('./Iris.csv')
iris.head()

iris.describe(include='all')

- 두 feature인 SepalLengCm, SepalWidthCm 산점도 그리기

fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111)

ax.scatter(x=iris['SepalLengthCm'], y=iris['SepalWidthCm'])
ax.set_xlabel('SepalLengthCm', fontsize=12)
ax.set_ylabel('SepalWidthCm', fontsize=12)
 
plt.show()

 

- SepalWidthCm의 평균을 기준으로 색을 다르게 표시하기

fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111)

slc_mean = iris['SepalLengthCm'].mean()
swc_mean = iris['SepalWidthCm'].mean()

ax.scatter(x=iris['SepalLengthCm'], 
           y=iris['SepalWidthCm'],
           c=['royalblue' if yy <= swc_mean else 'gray' for yy in iris['SepalWidthCm']]
           # c=['royalblue' if xx <= slc_mean else 'gray' for xx in iris['SepalLengthCm']]
          )
ax.set_xlabel('SepalLengthCm', fontsize=12)
ax.set_ylabel('SepalWidthCm', fontsize=12)
 
plt.show()

 

- 꽃의 종류에 따라 다르게 색깔 표시하기

fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111)

for species in iris['Species'].unique():
    iris_sub = iris[iris['Species']==species]
    ax.scatter(x=iris_sub['SepalLengthCm'], 
               y=iris_sub['SepalWidthCm'], 
               label=species)
    
ax.set_xlabel('SepalLengthCm', fontsize=12)
ax.set_ylabel('SepalWidthCm', fontsize=12)

ax.legend()    
plt.show()

 

- 두 feature인 SepalLengCm, SepalWidthCm 산점도 그리고 꽃의 종류에 따라 다르게 색칠하기

- 앞 그래프에 비해 좀 더 양의 상관관계를 분명하게 보이고 있고, 꽃의 종류 별로 군집화되어 있다

fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111)

for species in iris['Species'].unique():
    iris_sub = iris[iris['Species']==species]
    ax.scatter(x=iris_sub['PetalLengthCm'], 
               y=iris_sub['PetalWidthCm'], 
               label=species)
    
    
ax.set_xlabel('PetalLengthCm', fontsize=12)
ax.set_ylabel('PetalWidthCm', fontsize=12)

ax.legend()    
plt.show()

 

- 시각적인 주의를 주기 위해 선을 사용할 수도 있다

fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111)

for species in iris['Species'].unique():
    iris_sub = iris[iris['Species']==species]
    ax.scatter(x=iris_sub['PetalLengthCm'], 
               y=iris_sub['PetalWidthCm'], 
               label=species)

ax.axvline(2.5, color='gray', linestyle=':')    # 세로 선 그리기
ax.axhline(0.8, color='gray', linestyle=':')    # 가로 선 그리기

ax.set_xlabel('PetalLengthCm', fontsize=12)
ax.set_ylabel('PetalWidthCm', fontsize=12)

ax.legend()    
plt.show()

 

 

- 좀 더 다양한 관점에서 보기 위해, SepalLengthCm, SepalWidthCm, PetalLengthCm, PetalWidthCm 모두 비교

- 뒤에 배울 seaborn pairplot을 사용해 더 편리하게 표현 가능

fig, axes = plt.subplots(4, 4, figsize=(14, 14))

feat = ['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm']

for i, f1 in enumerate(feat):
    for j, f2 in enumerate(feat):
        if i <= j : 
            axes[i][j].set_visible(False)
            continue
        for species in iris['Species'].unique():
            iris_sub = iris[iris['Species']==species]
            axes[i][j].scatter(x=iris_sub[f2], 
                               y=iris_sub[f1], 
                               label=species, 
                               alpha=0.7)
        if i == 3: axes[i][j].set_xlabel(f2)
        if j == 0: axes[i][j].set_ylabel(f1)

plt.tight_layout()        
plt.show()