Python 데이터 시각화 기초: Matplotlib, Seaborn, Pandas Plot 제대로 사용하기

Alchemist·2026년 10월 6일

KT AIVLE

목록 보기
51/130

데이터를 표로만 보면 전체 패턴을 빠르게 파악하기 어렵다.

시각화를 사용하면 다음과 같은 질문에 더 쉽게 답할 수 있다.

  • 시간이 지나면서 값이 어떻게 변하는가?
  • 그룹별 차이는 얼마나 큰가?
  • 데이터는 어디에 몰려 있는가?
  • 두 변수는 함께 증가하는가?
  • 이상치가 있는가?

Python 데이터 분석에서는 주로 Matplotlib, Seaborn, 그리고 Pandas의 plot() 기능을 사용한다.


라이브러리 준비

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

Matplotlib는 기본 그래프 엔진 역할을 하고, Seaborn과 Pandas 시각화도 내부적으로 Matplotlib와 연결되는 경우가 많다.


가장 기본적인 선 그래프

days = [
    1,
    2,
    3,
    4,
    5,
]

users = [
    120,
    150,
    143,
    190,
    230,
]

plt.plot(
    days,
    users,
)

plt.xlabel("Day")
plt.ylabel("Users")
plt.title(
    "Daily Active Users"
)

plt.show()

선 그래프는 순서가 있는 값의 변화, 특히 시간 변화에 적합하다.


Figure와 Axes

Matplotlib를 제대로 사용하려면 두 객체를 구분하는 것이 좋다.

  • Figure: 전체 그림 영역
  • Axes: 실제 그래프가 그려지는 영역
fig, ax = plt.subplots()

ax.plot(
    days,
    users,
)

ax.set_title(
    "Daily Active Users"
)

ax.set_xlabel("Day")
ax.set_ylabel("Users")

plt.show()

간단한 그래프에서는 plt.plot()도 충분하지만, 그래프가 복잡해질수록 객체 지향 방식인 fig, ax를 사용하는 것이 관리하기 쉽다.


여러 그래프 배치하기

fig, axes = plt.subplots(
    1,
    2,
    figsize=(
        10,
        4,
    ),
)

첫 번째 그래프:

axes[0].plot(
    days,
    users,
)

axes[0].set_title(
    "Users"
)

두 번째 그래프:

revenue = [
    10,
    12,
    11,
    16,
    20,
]

axes[1].plot(
    days,
    revenue,
)

axes[1].set_title(
    "Revenue"
)

레이아웃 정리:

fig.tight_layout()

plt.show()

막대 그래프

범주별 값을 비교할 때 적합하다.

categories = [
    "Search",
    "Feed",
    "Profile",
]

counts = [
    320,
    510,
    180,
]

fig, ax = plt.subplots()

ax.bar(
    categories,
    counts,
)

ax.set_ylabel(
    "Clicks"
)

ax.set_title(
    "Clicks by Feature"
)

plt.show()

가로 막대 그래프

항목명이 길다면 가로 형태가 편할 수 있다.

fig, ax = plt.subplots()

ax.barh(
    categories,
    counts,
)

plt.show()

산점도

두 수치형 변수의 관계를 확인한다.

ad_spend = np.array(
    [
        10,
        20,
        30,
        40,
        50,
    ]
)

sales = np.array(
    [
        15,
        24,
        33,
        41,
        58,
    ]
)

fig, ax = plt.subplots()

ax.scatter(
    ad_spend,
    sales,
)

ax.set_xlabel(
    "Ad Spend"
)

ax.set_ylabel(
    "Sales"
)

plt.show()

두 변수가 함께 증가하는지, 이상한 점이 있는지 빠르게 확인할 수 있다.


히스토그램

수치형 데이터의 분포를 확인한다.

rng = np.random.default_rng(
    42
)

response_time = rng.normal(
    loc=200,
    scale=40,
    size=1000,
)

fig, ax = plt.subplots()

ax.hist(
    response_time,
    bins=30,
)

ax.set_xlabel(
    "Response Time (ms)"
)

ax.set_ylabel(
    "Count"
)

plt.show()

bins 값에 따라 그래프 인상이 크게 달라질 수 있으므로 여러 구간 수를 비교해보는 것이 좋다.


박스플롯

분포와 이상치를 빠르게 비교하는 데 유용하다.

fig, ax = plt.subplots()

ax.boxplot(
    response_time
)

plt.show()

박스플롯은 일반적으로 다음 정보를 보여준다.

  • 중앙값
  • 사분위 범위
  • 수염 범위
  • 이상치 후보

파이 차트는 언제 사용할까?

fig, ax = plt.subplots()

ax.pie(
    [
        50,
        30,
        20,
    ],
    labels=[
        "Web",
        "App",
        "Other",
    ],
    autopct="%.1f%%",
)

plt.show()

전체에서 몇 개 항목이 차지하는 비율을 단순하게 보여줄 때 사용할 수 있다.

하지만 항목이 많거나 값 차이가 작다면 막대 그래프가 비교하기 더 쉬운 경우가 많다.


그래프에 범례 추가하기

fig, ax = plt.subplots()

ax.plot(
    days,
    users,
    label="Users",
)

ax.plot(
    days,
    revenue,
    label="Revenue",
)

ax.legend()

plt.show()

축 범위와 눈금

ax.set_xlim(
    1,
    5,
)

ax.set_ylim(
    0,
    250,
)

눈금 직접 설정:

ax.set_xticks(
    [
        1,
        2,
        3,
        4,
        5,
    ]
)

축을 임의로 잘라 과장된 차이를 만들지 않도록 주의해야 한다.


Seaborn이 편한 이유

Seaborn은 Pandas DataFrame의 컬럼명을 직접 지정할 수 있고, 범주별 색상·스타일 같은 통계적 시각화를 편하게 구성할 수 있다.

예제 데이터:

df = pd.DataFrame(
    {
        "channel": [
            "search",
            "search",
            "feed",
            "feed",
            "profile",
            "profile",
        ],
        "session_time": [
            12,
            18,
            25,
            31,
            9,
            14,
        ],
        "purchase": [
            0,
            1,
            1,
            1,
            0,
            0,
        ],
    }
)

Seaborn 산점도

sns.scatterplot(
    data=df,
    x="session_time",
    y="purchase",
    hue="channel",
)

plt.show()

hue를 지정하면 그룹을 시각적으로 구분할 수 있다.

style, size도 데이터 의미에 따라 사용할 수 있지만, 너무 많은 시각 변수를 한 번에 넣으면 그래프가 복잡해질 수 있다.


Seaborn 히스토그램

sns.histplot(
    data=df,
    x="session_time",
    bins=5,
)

plt.show()

그룹별 분포:

sns.histplot(
    data=df,
    x="session_time",
    hue="channel",
)

plt.show()

필요하면 KDE를 함께 표시할 수도 있다.

sns.histplot(
    data=df,
    x="session_time",
    kde=True,
)

plt.show()

Box Plot

sns.boxplot(
    data=df,
    x="channel",
    y="session_time",
)

plt.show()

카테고리별 수치 분포 비교에 적합하다.


Violin Plot

sns.violinplot(
    data=df,
    x="channel",
    y="session_time",
    inner="box",
)

plt.show()

박스플롯보다 분포 형태를 더 자세하게 보여준다.

데이터가 너무 적으면 밀도 모양을 과하게 해석하지 않도록 주의해야 한다.


실제 관측값을 같이 보기

sns.boxplot(
    data=df,
    x="channel",
    y="session_time",
)

sns.stripplot(
    data=df,
    x="channel",
    y="session_time",
)

plt.show()

요약 통계와 실제 점을 함께 보면 데이터 수와 분포를 더 정확하게 이해할 수 있다.


Pandas에서 바로 그래프 그리기

Series와 DataFrame에는 plot() 메서드가 있다.

sales = pd.Series(
    [
        120,
        150,
        180,
    ],
    index=[
        "Jan",
        "Feb",
        "Mar",
    ],
)

sales.plot()

plt.show()

막대 그래프

sales.plot.bar()

plt.show()

히스토그램

df["session_time"].plot.hist(
    bins=5
)

plt.show()

박스플롯

df[
    [
        "session_time",
        "purchase",
    ]
].plot.box()

plt.show()

산점도

DataFrame의 두 컬럼:

numeric_df = pd.DataFrame(
    {
        "clicks": [
            3,
            5,
            8,
            10,
        ],
        "orders": [
            0,
            1,
            2,
            4,
        ],
    }
)

numeric_df.plot.scatter(
    x="clicks",
    y="orders",
)

plt.show()

간단한 EDA에서는 Pandas plot()이 빠르고 편하다.

세밀한 제어가 필요하면 Matplotlib나 Seaborn으로 확장할 수 있다.


그룹 분석 결과 시각화

summary = (
    df
    .groupby(
        "channel"
    )["session_time"]
    .mean()
)

summary.plot.bar()

plt.ylabel(
    "Average Session Time"
)

plt.show()

Pandas 분석 결과를 바로 그래프로 이어갈 수 있다.


시계열 데이터 시각화

dates = pd.date_range(
    start="2026-09-01",
    periods=30,
    freq="D",
)

rng = np.random.default_rng(
    42
)

traffic = pd.Series(
    rng.integers(
        100,
        300,
        size=30,
    ),
    index=dates,
)
fig, ax = plt.subplots(
    figsize=(
        10,
        4,
    )
)

ax.plot(
    traffic.index,
    traffic.values,
)

ax.set_title(
    "Daily Traffic"
)

plt.show()

시간의 흐름이 있는 데이터는 날짜 순서를 유지하는 것이 중요하다.


이동 평균을 함께 표시하기

moving_average = (
    traffic
    .rolling(
        window=7
    )
    .mean()
)

fig, ax = plt.subplots(
    figsize=(
        10,
        4,
    )
)

ax.plot(
    traffic.index,
    traffic.values,
    label="Daily",
)

ax.plot(
    moving_average.index,
    moving_average.values,
    label="7-day MA",
)

ax.legend()

plt.show()

원 데이터의 단기 변동과 추세를 함께 볼 수 있다.


어떤 그래프를 선택해야 할까?

질문추천 그래프
시간에 따른 변화선 그래프
범주별 크기 비교막대 그래프
두 수치 변수 관계산점도
하나의 수치 분포히스토그램
그룹별 분포 비교박스플롯 / 바이올린플롯
전체 중 몇 개 범주 비율파이 차트
2차원 격자 값heatmap / image 계열

그래프 종류보다 분석 질문에 맞는 시각화인지가 더 중요하다.


삼각형 기반 비정형 격자 시각화

일반적인 데이터 분석에서는 자주 사용하지 않지만, 관측 지점이 규칙적인 직사각형 격자가 아닐 때 Matplotlib의 삼각 분할 기반 그래프를 사용할 수 있다.

관련 함수:

plt.triplot(...)
plt.tripcolor(...)
plt.tricontour(...)
plt.tricontourf(...)

지리 좌표, 물리 시뮬레이션, 비정형 메시 데이터 같은 특별한 상황에서 유용하다.

일반 EDA 입문 단계에서는 선·막대·산점도·히스토그램·박스플롯을 먼저 익히는 것이 우선이다.


그래프를 저장하기

fig, ax = plt.subplots()

ax.plot(
    days,
    users,
)

fig.savefig(
    "daily-users.png",
    dpi=150,
    bbox_inches="tight",
)

plt.show() 전에 저장하는 흐름이 이해하기 쉽다.


시각화에서 자주 하는 실수

데이터 타입을 확인하지 않기

숫자처럼 보이는 문자열:

"100"
"200"
"300"

먼저 숫자로 변환해야 한다.

df["amount"] = pd.to_numeric(
    df["amount"],
    errors="coerce",
)

날짜를 문자열 순서로 그리기

날짜는 datetime으로 변환하고 정렬한다.

df["date"] = pd.to_datetime(
    df["date"]
)

df = df.sort_values(
    "date"
)

그래프를 너무 많이 꾸미기

색상, 마커, 라벨을 과도하게 넣으면 분석 대상보다 장식이 더 눈에 띌 수 있다.

시각화의 목표는 데이터를 더 쉽게 이해하는 것이다.


평균만 시각화하기

평균 막대 하나만 보면 분포와 이상치를 알 수 없다.

가능하다면 다음을 함께 고려한다.

  • 실제 관측값
  • 히스토그램
  • 박스플롯
  • 오차 범위
  • 샘플 수

실전 EDA 흐름

데이터를 받으면 다음 순서로 시각화해볼 수 있다.

1. 수치형 변수 분포

sns.histplot(
    data=df,
    x="session_time",
)

2. 범주별 비교

sns.boxplot(
    data=df,
    x="channel",
    y="session_time",
)

3. 두 변수 관계

sns.scatterplot(
    data=numeric_df,
    x="clicks",
    y="orders",
)

4. 시간 변화

ax.plot(
    traffic.index,
    traffic.values,
)

이 정도만 익혀도 탐색적 데이터 분석에서 필요한 기본적인 질문을 상당 부분 확인할 수 있다.


핵심 정리

  • Matplotlib는 Python 시각화의 기본 도구이며 Figure와 Axes 구조를 이해하면 복잡한 그래프를 다루기 쉬워진다.
  • 선 그래프는 변화, 막대 그래프는 범주 비교, 산점도는 변수 관계, 히스토그램은 분포를 확인하는 데 적합하다.
  • Seaborn은 DataFrame 기반 통계 시각화를 편리하게 작성할 수 있다.
  • histplot, boxplot, violinplot, scatterplot을 익히면 기본적인 EDA에 충분히 활용할 수 있다.
  • Pandas의 plot() 메서드는 분석 결과를 빠르게 시각화할 때 편리하다.
  • 시계열 그래프에서는 날짜 타입과 정렬 상태를 먼저 확인해야 한다.
  • 그래프를 고를 때는 모양보다 어떤 분석 질문에 답하려는지 먼저 생각하는 것이 중요하다.
  • 평균만 보는 것보다 분포, 이상치, 실제 관측값을 함께 확인하는 것이 데이터 해석에 도움이 된다.
profile
html_programming_language

0개의 댓글