시작하며

동일한 기술통계량을 가지고 있더라도 데이터의 분포는 전혀 다를 수 있다. 앤스콤 사인방(Anscombe’s quartet) 예시는 이 점을 잘 보여주며, 데이터를 분석할 때 시각화가 왜 중요한지 명확하게 알려준다. 이 포스팅에서는 앤스콤 사인방과 함께 수치형·범주형 변수의 주요 시각화 방법을 정리한다.

앤스콤 사인방(Anscombe’s quartet)

앤스콤 사인방은 동일한 기술통계량을 가지고 있지만 매우 다른 분포를 가진 4개의 데이터셋이다.

import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
 
# Mac의 경우 그래프의 한글 환경설정
matplotlib.rc('font', family='AppleGothic')
 
anscombe = sns.load_dataset("anscombe")
anscombe.shape
 
anscombe.head()
 
anscombe.dataset.value_counts()
anscombe.groupby('dataset').mean()  # 평균값
anscombe.groupby('dataset').std()   # 표준편차
anscombe.groupby('dataset').corr()  # 상관계수
 
ans1 = anscombe[anscombe.dataset == 'I']
ans2 = anscombe[anscombe.dataset == 'II']
ans3 = anscombe[anscombe.dataset == 'III']
ans4 = anscombe[anscombe.dataset == 'IV']
 
fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(6, 6))
 
sns.scatterplot(x='x', y='y', data=ans1, ax=axs[0, 0])  # ax는 그림이 들어가는 위치를 의미.
sns.scatterplot(x='x', y='y', data=ans2, ax=axs[0, 1])
sns.scatterplot(x='x', y='y', data=ans3, ax=axs[1, 0])
sns.scatterplot(x='x', y='y', data=ans4, ax=axs[1, 1])
 
axs[0, 0].set_title("dataset I")
axs[0, 1].set_title("dataset II")
axs[1, 0].set_title("dataset III")
axs[1, 1].set_title("dataset IV")
 
fig.tight_layout()  # 그래프들 간의 간격 띄우기 위함
plt.show()

수치형 데이터(numerical data) 시각화

import pandas as pd
apt = pd.read_excel('data/아파트_실거래가_서울.xlsx')
apt.rename(columns={'전용면적(㎡)': '면적', '거래금액(만원)': '가격'}, inplace=True)
apt['단가'] = apt.가격 / apt.면적
 
# 히스토그램
sns.histplot(apt.단가)
plt.show()
 
# 단위면적당 가격의 분포를 보여주는 히스토그램. 오른쪽에 긴 꼬리가 있는 분포임을 한눈에 볼 수 있음
sns.histplot(apt.단가, bins=10)  # 구간의 수를 인위로 정할 수 있음
plt.show()
 
# subplot으로 2개를 그린다.
# 광진구는 왼쪽으로 꼬리가 있는 왜도가 음수인 분포, 노원구는 오른쪽으로 꼬리가 있는 왜도가 양수인 분포
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 5))
 
sns.histplot(apt.단가[apt.구 == '광진구'], ax=ax[0], kde=True)  # kde=True: 커널밀도추정함수를 히스토그램에 추가
sns.histplot(apt.단가[apt.구 == '노원구'], ax=ax[1], kde=True)
 
ax[0].set_title("단가(광진구)")
ax[1].set_title("단가(노원구)")
 
plt.show()
 
# box plot
# 히스토그램에서는 이상치 여부를 알 수 없지만 상자그림에서는 이상치와 기술통계량에 대한 추가 정보를 얻을 수 있음
sns.boxplot(data=apt, x='단가', showmeans=True)
plt.show()
 
# 산점도(scatter) plot
# 면적이 증가할수록 가격이 증가하는 모습, 즉 우상향하는 트렌드
sns.scatterplot(data=apt, x='면적', y='가격')
plt.show()
 
# 산점도 행렬(pair plot)
# 단가, 가격, 면적 변수들의 관계를 한눈에 볼 수 있음
nw = apt.loc[apt.구 == '노원구', ['구', '단가', '가격', '면적']]
 
sns.pairplot(nw)
plt.show()

범주형 데이터(categorical data) 시각화

import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
 
# Mac의 경우 그래프의 한글 환경설정
matplotlib.rc('font', family='AppleGothic')
 
import pandas as pd
apt = pd.read_excel('data/아파트_실거래가_서울.xlsx')
apt.rename(columns={'전용면적(㎡)': '면적', '거래금액(만원)': '가격'}, inplace=True)
apt['단가'] = apt.가격 / apt.면적
apt.columns
 
# bar plot : 25개의 구
tb = apt.구.value_counts().sort_values()
sns.barplot(y=tb.index, x=tb.values)  # tb.index: 구 이름, tb.values: 빈도수(frequency)
plt.show()
 
# pie chart
plt.pie(x=tb.values, labels=tb.index)
plt.show()
 
# 수치형 변수와 범주형 변수를 결합한 시각화
gj_nw = apt[apt.구.isin(['광진구', '노원구'])]
sns.histplot(data=gj_nw, x='단가', hue='구')
plt.show()

정리하며

앤스콤 사인방의 예시에서 보듯, 기술통계량이 동일하더라도 데이터의 분포는 전혀 다를 수 있다. 따라서 데이터를 분석할 때는 수치적 요약과 함께 반드시 시각화를 병행해야 한다. 수치형 데이터는 히스토그램·박스플롯·산점도를 통해, 범주형 데이터는 바차트·파이차트를 통해 분포와 관계를 직관적으로 확인할 수 있다.