[Data viz] 데이터 시각화와 기본적인 차트

데이터 시각화

데이터셋의 종류

  • 정형 데이터
  • 시계열 데이터
  • 지리 / 지도 데이터 : 거리, 경로, 분포
  • 관계 데이터 : 객체 간의 관계를 시각화 (객체는 Node, 관계는 Link)
  • 계층적 데이터

데이터 종류

  • 수치형(numerical)
    • 연속형(continuous) : 길이, 무게, 온도
    • 이산형(discrete) : 눈금, 사람 수
  • 범주형(categorical)
    • 명목형(nominal) : 혈액형
    • 순서형(ordinal) : 학년, 별점

Pre-attentive Attribute(전주의적 속성)

주의를 주지 않아도 사람이 자연스럽게 인지하게 되는 요소

Matplotlib

1
2
3
4
5
6
7
8
import numpy as np 
import matplotlib as mpl

fig = plt.figure() # 기본적으로 figure 객체(큰 틀)에
ax = fig.add_subplot() # ax 같은 서브플롯을 추가해서 그린다.
plt.show()

# fig = plt.figure(figsize=(12, 7)) 이렇게 사이즈 조절도 가능
1
2
3
4
5
fig = plt.figure()
ax = fig.add_subplot(121) # 1 by 2로 쪼갠 것의 첫 번째
# ax = fig.add_subplot(1, 2, 1)로 사용가능
ax = fig.add_subplot(122) 
plt.show()
1
2
3
4
5
6
7
8
9
10
11
fig = plt.figure()
ax = fig.add_subplot(111) 

# plt에 그리지 않고, ax 객체에 직접 그리는 동시에
ax.plot([1, 1, 1], label='1')  
ax.plot([2, 2, 2], label='2') 
ax.plot([3, 3, 3], label='3')

# 범례 추가하기
ax.legend()
plt.show()

데이터 확인 함수

feature를 알기 위해서 주로 head(), describe(), info() 함수들이 쓰인다.
종류나 큰 분포는 unique(), value_counts() 이걸로 알아보자.




bar plot

막대 그래프이다. bar() 또는 barh() 함수를 쓰면 된다. 범주에 따른 수치 값을 비교하기에 적합하다.

데이터가 여러 개 있다면, 다음과 같은 방법으로 표현할 수 있을 것이다.

  • Stacked Bar Plot
  • Overlapped Bar Plot
  • Grouped Bar Plot

Stacked Bar Plot

먼저 두 개 이상의 그룹 데이터를 쌓아서 표현하는 방법이다. 당연히 각각의 막대마다 그룹이 쌓여지는 순서는 동일해야 한다.
문제는 그저 그룹별로 쌓아서 표현하는 방식이기에 맨 아래에 위치한 그룹 외에는 데이터에 대한 파악이 힘들다는 단점이 있다.

bar()를 사용할 땐(수직 그래프) bottom 파라미터로 아래에 위치할 그룹을 지정할 수 있다.
barh()를 사용할 땐(수평 그래프) left 파라미터로 왼쪽에 위치할 그룹을 지정할 수 있다.

위에서 언급한 단점을 해소하기 위해서 Percentage Stacked Bar Chart가 있다. 이는 각 그룹이 특정 범주(막대)에서 차지하는 비율을 보여준다.

Overlapped Bar Plot

두 개 그룹만 비교한다면 겹쳐서 만드는 게 좋다. 어차피 같은 축을 사용하니까 그냥 쌓아서 표현하는 방법보다 더 나은 것 같다. 겹치는 부분의 투명도를 조정해서 표현한다.
물론 막대 그래프로 이렇게 표현할 바에 area plot을 사용해서 표현한다면 좀 더 나을 것이다.

Grouped Bar Plot

이건 그냥 그룹별 같은 범주에 속하는 막대를 이웃하게 배치하는 방법이다.
다만 matplotlib에서는 구현하기가 조금 까다롭다. .set_xticks(), .set_xticklabels() 사용.

생각할 것

어떤 그래프를 사용하든지 그룹의 정렬은 필요하다. 데이터의 종류에 따라 기준을 정해서 그룹을 정렬하자.
Pandas에서는 sort_values(), sort_index()를 사용하여 정렬한다.

가독성을 향상시키기 위해서 여백을 활용하는 게 좋다.

  • 축 범위 설정 : .set_xlim(), .set_ylime()
  • 차트 테두리 제거 여부 : .spines[‘left’].set_visible()
  • 두께 설정 : width
  • 범례 : .legend()
  • 가장자리 공간 : .margins()

심플한 게 최고일 수 있다. 복잡함은 지양해야 한다.

  • 그리드 설정 : .grid()
  • 축 눈금 표시 : .set_ticklabels()
  • 글이나 주석 삽입 : .text(), .annotate()
  • 제목 설정 : .set_title()
  • 레이블 설정 : .set_xlabel(), .set_ylabel()

오차의 범위도 표현 가능하다(errorbar).

line plot

시간이나 순서에 따라 변하는 연속적인 값을 표현하기에 좋다.
시시각각으로 변동하는 데이터는 smoothing으로 대략적인 추이 파악만 가능하도록 만들 수 있다.

  • 막대 그래프와 달리 선 그래프는 추세에 집중하는 경우가 많으므로 축을 반드시 0에 둘 필요가 없다.
  • 너무 구체적인 선 그래프보단 일부 정보는 생략된 편이 나을 수 있다. 그리드는 주석 따위를 제거하고
  • 디테일한 정보는 표로 제공하는 게 좋다.
  • 생략되지 않는 선에서 범위를 조정해서 변화율 관찰 .set_ylim()

근데 선 그래프 특성상 기울기가 중요하다. 따라서 축의 간격이 중요하다. 규칙적인 간격이 아니면 관찰자가 오해할 수 있기에 관측값에 마커로 표시를 해주는 게 좋다.

보간은 트렌드를 보여주기엔 좋다만 일반적인 분석에선 지양하자

한 플롯에 대해 2개의 축을 사용하는 걸 이중 축이라고 한다.
예를 들어 같은 시간 축에 대해 서로 다른 종류의 데이터 표현하거나(.twinx()), 한 데이터에 대해 다른 단위로 보여주는 방식이 있다(secondary_xaxis(), secondary_yaxis()).
근데 그냥 표를 두 개 그리는 게 좋다.

라인 끝에 레이블을 추가하면 식별에 도움

그래프에 최소 최대 정보 표시를 추가해주면 좋다.

연한 색으로 오차범위 면적 같은 부분을 칠해서 표시해 줄 수도 있다.


scatter plot

산점도.

.scatter() 함수로 그린다. 두 피쳐 간의 상관 관계를 알기 위해 사용하거나 혹은 군집, 값 사이의 차이, 이상치를 알기 위해 사용한다.

overplotting

점이 많아질수록 점의 분포를 파악하기 힘들다. 투명도 조정, 지터링(점 위치 약간 변경), 2차원 히스토그램(히트맵으로 시각화), Contour plot(등고선)으로 문제를 해결할 수 있다.

인과 관계와 상관 관계를 헷갈리지 말자. 인과 관계는 항상 사전 정보와 함께 가설로 제시할 것.

추세선을 사용하면 산점도의 패턴을 알 수 있다.

산점도에서 그리드는 지양하는 게 좋다. 어차피 점이 크다면 그리드가 무용지물이 될 수도 있기 때문이다. 범주형이 포함된 관계에서는 heatmap 또는 bubble chart를 쓰는 게 더 좋을 것이다.