학습 목표
- matplotlib의 기본 플롯 구조(figure–plot–show)를 이해하고 그릴 수 있다
- seaborn의 countplot/histplot/boxplot으로 분포를 시각화할 수 있다
- 상관관계 heatmap으로 특성 간 관계를 읽을 수 있다
- 학습곡선을 그려 모델의 과적합 여부를 판단할 수 있다
시각화는 EDA에서 "숫자로는 안 보이는 것을 눈으로 확인하는" 단계입니다. JS 개발자라면 Chart.js나 D3로 그려 봤을 것입니다. Python 생태계에서는 matplotlib(저수준 엔진)과 그 위에 얹힌 seaborn(통계 플롯 특화)이 사실상 표준입니다. AICE 실기에서는 분포·상관·학습곡선을 그리는 문항이 반복됩니다.
📦 설치 안내: 이 챕터의 플롯을 로컬에서 실습하려면 다음 패키지가 필요합니다(기본 파이썬 환경에는 없을 수 있습니다).
pip install matplotlib seabornJupyter에서는
%matplotlib inline을 한 번 실행하면 셀 아래에 그림이 바로 표시됩니다.
matplotlib의 정신 모델은 "빈 도화지(figure)에 요소를 쌓고 마지막에 보여준다(show)"입니다. Chart.js가 설정 객체를 넘기는 선언형이라면, matplotlib는 명령을 순서대로 쌓는 명령형에 가깝습니다.
| JavaScript (Chart.js) | Python (matplotlib) |
|---|---|
new Chart(ctx, {type:'line', ...}) |
plt.plot(x, y) |
chart.options.title |
plt.title("...") |
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [1, 4, 9, 16, 25]
plt.figure(figsize=(6, 4)) # 도화지 크기(가로, 세로 인치)
plt.plot(x, y, marker="o") # 선 + 점
plt.title("y = x^2")
plt.xlabel("x")
plt.ylabel("y")
plt.show() # 화면에 표시여러 그래프를 나란히 놓을 때는 subplots를 씁니다. 반환된 축(ax) 객체에 그립니다.
fig, axes = plt.subplots(1, 2, figsize=(10, 4)) # 1행 2열
axes[0].plot(x, y)
axes[0].set_title("Line")
axes[1].scatter(x, y) # 산점도
axes[1].set_title("Scatter")
plt.tight_layout() # 겹침 방지
plt.show()
⚠️ 함정: matplotlib는 "현재 활성 figure"라는 전역 상태를 씁니다.plt.plot을 연달아 호출하면 같은 그림에 겹쳐 그려집니다. 새 그림을 원하면plt.figure()로 새 도화지를 열거나, 위처럼subplots로 축을 명시적으로 다루세요. JS의 캔버스별 독립 컨텍스트와 달리 상태가 공유됩니다.
seaborn은 DataFrame을 직접 받아 통계 플롯을 그립니다. data=에 DataFrame, x=/y=에 열 이름 문자열을 넘기는 패턴이 일관됩니다. 실기 빈출 3종을 봅니다.
countplot은 범주형 열의 빈도를 셉니다(막대그래프). df["col"].value_counts()를 그림으로 보는 것입니다.
import seaborn as sns
import pandas as pd
df = pd.DataFrame({
"city": ["Seoul", "Busan", "Seoul", "Daegu", "Seoul", "Busan"],
"age": [25, 30, 35, 28, 42, 33],
})
sns.countplot(data=df, x="city") # 도시별 개수
plt.title("City Counts")
plt.show()histplot은 수치형 열의 분포를 구간(bin)으로 나눠 봅니다. kde=True를 주면 밀도 곡선을 겹칩니다.
sns.histplot(data=df, x="age", bins=10, kde=True)
plt.title("Age Distribution")
plt.show()boxplot은 사분위수·이상치를 한눈에 보여줍니다. 범주별 분포 비교에 유용합니다(x에 범주, y에 수치).
sns.boxplot(data=df, x="city", y="age") # 도시별 나이 분포
plt.title("Age by City")
plt.show()🎯 AICE:
countplot(범주 빈도),histplot(수치 분포),boxplot(이상치 확인)은 실기 EDA 문항에서 "분포를 시각화하라"는 지시에 그대로 대응합니다.sns.countplot(data=df, x='컬럼')처럼data와x인자를 빈칸으로 두는 형태가 자주 출제되니 인자 이름을 정확히 외우세요.
수치형 특성들이 서로 얼마나 함께 움직이는지를 봅니다. df.corr()가 상관계수 행렬(−1~1)을 만들고, sns.heatmap이 색으로 표현합니다. 상관이 높은 특성 쌍을 찾아 다중공선성을 점검하는 EDA 단골입니다.
num_df = pd.DataFrame({
"age": [25, 30, 35, 40, 45],
"income": [2000, 2500, 4000, 5000, 7000],
"score": [80, 70, 75, 60, 55],
})
corr = num_df.corr() # 상관계수 행렬
sns.heatmap(corr, annot=True, cmap="coolwarm", vmin=-1, vmax=1)
plt.title("Correlation Heatmap")
plt.show()annot=True는 셀에 숫자를 표시하고, cmap은 색 팔레트, vmin/vmax로 색 범위를 −1~1에 고정합니다.
⚠️ 함정:df.corr()는 수치형 열만 대상으로 계산합니다. 문자열 열이 섞여 있으면 자동으로 제외되거나 버전에 따라 에러가 날 수 있으니,df.select_dtypes(include="number").corr()처럼 수치형만 골라 넘기는 습관이 안전합니다.
모델을 학습시키면(18장 Keras) epoch별 손실(loss)과 정확도가 기록됩니다. 이를 학습(train) vs 검증(validation) 두 선으로 그리면 과적합을 판단할 수 있습니다. 검증 손실이 다시 올라가기 시작하는 지점이 과적합의 신호입니다.
# history는 model.fit(...)이 반환하는 객체 (18장 참조)
epochs = range(1, 11)
train_loss = [0.9, 0.7, 0.55, 0.45, 0.38, 0.33, 0.30, 0.28, 0.27, 0.26]
val_loss = [0.95, 0.75, 0.60, 0.52, 0.50, 0.51, 0.55, 0.60, 0.66, 0.72]
plt.figure(figsize=(6, 4))
plt.plot(epochs, train_loss, label="train")
plt.plot(epochs, val_loss, label="validation")
plt.xlabel("epoch")
plt.ylabel("loss")
plt.legend() # 범례 표시
plt.title("Learning Curve")
plt.show()
# 검증 손실이 5 epoch 부근부터 상승 → 과적합 시작🎯 AICE: 딥러닝 문항에서
history.history['loss']와history.history['val_loss']를 꺼내 두 선을 그리는 학습곡선 시각화가 마무리 단계로 나옵니다.plt.plot(..., label=...)뒤에plt.legend()를 빠뜨려 범례가 안 나오는 실수가 잦으니 짝으로 외우세요.
Q1. 범주형 열 grade의 빈도를 막대그래프로 그리려 합니다. 빈칸을 채우세요.
import seaborn as sns
sns.____(data=df, x="grade")
plt.show()정답
import seaborn as sns
sns.countplot(data=df, x="grade")
plt.show()범주별 개수를 세는 것은 countplot입니다. 수치 분포라면 histplot을 씁니다.
Q2. 수치형 특성들의 상관계수 행렬을 heatmap으로 그리려 합니다. 빈칸을 채우세요.
corr = df.____()
sns.heatmap(corr, annot=True, cmap="coolwarm")
plt.show()정답
corr = df.corr()
sns.heatmap(corr, annot=True, cmap="coolwarm")
plt.show()df.corr()가 상관계수 행렬을 만들고, annot=True로 각 셀에 값을 표시합니다.
Q3. 학습곡선에서 검증 손실 선에 범례가 나오도록 하려 합니다. 빈칸을 채우세요.
plt.plot(epochs, val_loss, ____="validation")
plt.legend()
plt.show()정답
plt.plot(epochs, val_loss, label="validation")
plt.legend()
plt.show()plot의 label 인자로 선 이름을 지정하고, plt.legend()가 그 라벨들을 범례로 표시합니다.
| JS (Chart.js 계열) | Python (matplotlib/seaborn) | 비고 |
|---|---|---|
new Chart(ctx, {type:'line'}) |
plt.plot(x, y) |
선 그래프 |
type: 'bar' + 집계 |
sns.countplot(data, x=...) |
범주 빈도 |
| 히스토그램 플러그인 | sns.histplot(data, x=..., bins=...) |
수치 분포 |
| (대응 없음) | sns.boxplot(data, x=, y=) |
사분위·이상치 |
| 히트맵 플러그인 | sns.heatmap(df.corr(), annot=True) |
상관관계 |
| 여러 캔버스 | plt.subplots(행, 열) |
격자 배치 |
데이터셋 label |
plt.plot(..., label=...)+plt.legend() |
범례 |