volunteer#봉사#파이썬#Python#NumPy#Pandas#Matplotlib#Seaborn

붓꽃 데이터 시각화 심화 실습

풍생고등학교 코딩봉사 4주차-2 NumPy, Pandas, Matplotlib, Seaborn을 활용해 붓꽃(Iris) 데이터셋을 단계별로 분석하고 시각화하는 심화 실습

2026년 5월 29일2분 읽기조회 24
공유

🌸 저번 시간에 배운 NumPy · Pandas · Matplotlib · Seaborn을 모두 활용하는 종합 실습이에요!


붓꽃(Iris) 데이터셋이란?

데이터 분석 입문에서 가장 많이 쓰이는 유명한 데이터셋이에요.

붓꽃 3종류 — Setosa, Versicolor, Virginica — 각 50개, 총 150개의 꽃 측정 데이터가 담겨 있어요.

컬럼명한국어설명
sepal_length꽃받침 길이단위: cm
sepal_width꽃받침 너비단위: cm
petal_length꽃잎 길이단위: cm
petal_width꽃잎 너비단위: cm
species품종setosa / versicolor / virginica

💡 Seaborn에 내장되어 있어서 sns.load_dataset("iris")로 바로 불러올 수 있어요!


STEP 1. 데이터 불러오기 & 탐색

목표: 데이터가 어떻게 생겼는지 파악해요.

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

# 데이터 불러오기
df = sns.load_dataset("iris")

# 기본 탐색
print("=== 처음 5행 ===")
print(df.head())

print("\n=== 데이터 크기 ===")
print(df.shape)       # (150, 5)

print("\n=== 열 정보 ===")
print(df.info())

print("\n=== 통계 요약 ===")
print(df.describe())

print("\n=== 품종별 개수 ===")
print(df["species"].value_counts())

실행 결과 예시

=== 처음 5행 ===
   sepal_length  sepal_width  petal_length  petal_width species
0           5.1          3.5           1.4          0.2  setosa
1           4.9          3.0           1.4          0.2  setosa
...

=== 품종별 개수 ===
species
setosa        50
versicolor    50
virginica     50

❓ 생각해보기: 150개 행, 5개 열이 맞게 출력됐나요? df.describe()에서 평균과 최댓값을 확인해보세요.


STEP 2. NumPy로 통계 계산하기

목표: Pandas 없이 NumPy만으로 직접 통계를 계산해봐요.

import numpy as np
import seaborn as sns

df = sns.load_dataset("iris")

# 꽃잎 길이(petal_length) 배열로 추출
petal_lengths = df["petal_length"].to_numpy()

print("=== 꽃잎 길이 통계 ===")
print(f"평균:    {np.mean(petal_lengths):.2f} cm")
print(f"표준편차: {np.std(petal_lengths):.2f} cm")
print(f"최솟값:  {np.min(petal_lengths):.2f} cm")
print(f"최댓값:  {np.max(petal_lengths):.2f} cm")
print(f"중앙값:  {np.median(petal_lengths):.2f} cm")

# 품종별로 나눠서 계산
for species in df["species"].unique():
    subset = df[df["species"] == species]["petal_length"].to_numpy()
    print(f"\n[{species}] 꽃잎 길이 평균: {np.mean(subset):.2f} cm")

실행 결과 예시

=== 꽃잎 길이 통계 ===
평균:    3.76 cm
표준편차: 1.77 cm
최솟값:  1.00 cm
최댓값:  6.90 cm
중앙값:  4.35 cm

[setosa] 꽃잎 길이 평균: 1.46 cm
[versicolor] 꽃잎 길이 평균: 4.26 cm
[virginica] 꽃잎 길이 평균: 5.55 cm

❓ 생각해보기: 품종별 평균 차이가 꽤 크네요! 이걸 그래프로 그리면 어떻게 보일까요?


STEP 3. Pandas로 품종별 집계

목표: groupby를 활용해서 품종별 특성을 비교해요.

import seaborn as sns

df = sns.load_dataset("iris")

# 품종별 평균 (모든 수치 컬럼)
print("=== 품종별 평균 ===")
print(df.groupby("species").mean().round(2))

# 품종별 꽃잎 길이 최대·최솟값
print("\n=== 품종별 꽃잎 길이 범위 ===")
print(df.groupby("species")["petal_length"].agg(["min", "max", "mean"]).round(2))

# 꽃잎 길이가 5cm 이상인 행만 필터링
big_petal = df[df["petal_length"] >= 5.0]
print(f"\n꽃잎 길이 5cm 이상: {len(big_petal)}개")
print(big_petal["species"].value_counts())

실행 결과 예시

=== 품종별 평균 ===
            sepal_length  sepal_width  petal_length  petal_width
species
setosa              5.01         3.43          1.46         0.25
versicolor          5.94         2.77          4.26         1.33
virginica           6.59         2.97          5.55         2.03

꽃잎 길이 5cm 이상: 42개
species
virginica     36
versicolor     6

❓ 생각해보기: agg(["min", "max", "mean"])처럼 집계 함수를 여러 개 한 번에 적용할 수 있어요. 다른 컬럼도 해보세요!


STEP 4. Matplotlib으로 기본 시각화

목표: 막대 그래프와 산점도로 데이터를 직접 그려봐요.

import matplotlib.pyplot as plt
import seaborn as sns

df = sns.load_dataset("iris")

# 한글 폰트 설정 (필요한 경우)
plt.rcParams["axes.unicode_minus"] = False

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# 왼쪽: 품종별 평균 꽃잎 길이 막대 그래프
species_mean = df.groupby("species")["petal_length"].mean()
colors = ["#FF9AA2", "#C7CEEA", "#B5EAD7"]

axes[0].bar(species_mean.index, species_mean.values, color=colors)
axes[0].set_title("품종별 평균 꽃잎 길이", fontsize=14)
axes[0].set_xlabel("품종")
axes[0].set_ylabel("꽃잎 길이 (cm)")
axes[0].set_ylim(0, 7)

for i, (name, val) in enumerate(species_mean.items()):
    axes[0].text(i, val + 0.1, f"{val:.2f}", ha="center", fontsize=11)

# 오른쪽: 꽃받침 길이 vs 꽃잎 길이 산점도
color_map = {"setosa": "#FF9AA2", "versicolor": "#C7CEEA", "virginica": "#B5EAD7"}

for species, group in df.groupby("species"):
    axes[1].scatter(
        group["sepal_length"],
        group["petal_length"],
        label=species,
        color=color_map[species],
        edgecolors="gray",
        alpha=0.7
    )

axes[1].set_title("꽃받침 길이 vs 꽃잎 길이", fontsize=14)
axes[1].set_xlabel("꽃받침 길이 (cm)")
axes[1].set_ylabel("꽃잎 길이 (cm)")
axes[1].legend()
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

💡 fig, axes = plt.subplots(1, 2) — 그래프를 1행 2열로 나란히 그릴 수 있어요!
tight_layout()은 그래프 간격을 자동으로 조정해줘요. ❓ 생각해보기: 산점도에서 setosa는 확실히 분리되는데, versicolor와 virginica는 좀 섞이죠? 이게 무슨 의미일까요?


STEP 5. Seaborn으로 고급 시각화

목표: Seaborn의 특화 차트로 분포와 상관관계를 한눈에 파악해요.

import seaborn as sns
import matplotlib.pyplot as plt

df = sns.load_dataset("iris")

fig, axes = plt.subplots(2, 2, figsize=(13, 10))
fig.suptitle("🌸 Iris 데이터셋 종합 분석", fontsize=16, fontweight="bold")

# (1) 박스플롯 — 품종별 꽃잎 길이 분포
sns.boxplot(
    data=df, x="species", y="petal_length",
    palette=["#FF9AA2", "#C7CEEA", "#B5EAD7"],
    ax=axes[0, 0]
)
axes[0, 0].set_title("품종별 꽃잎 길이 분포 (박스플롯)")
axes[0, 0].set_xlabel("품종")
axes[0, 0].set_ylabel("꽃잎 길이 (cm)")

# (2) 바이올린 플롯 — 박스플롯보다 분포 모양을 더 잘 보여줌
sns.violinplot(
    data=df, x="species", y="sepal_width",
    palette=["#FF9AA2", "#C7CEEA", "#B5EAD7"],
    ax=axes[0, 1]
)
axes[0, 1].set_title("품종별 꽃받침 너비 분포 (바이올린)")
axes[0, 1].set_xlabel("품종")
axes[0, 1].set_ylabel("꽃받침 너비 (cm)")

# (3) 히트맵 — 수치 컬럼 간 상관관계
numeric_df = df.drop(columns=["species"])
corr = numeric_df.corr()
sns.heatmap(
    corr, annot=True, fmt=".2f",
    cmap="coolwarm", center=0,
    ax=axes[1, 0]
)
axes[1, 0].set_title("컬럼 간 상관관계 히트맵")

# (4) 산점도 + 회귀선 — 꽃잎 길이와 너비의 관계
sns.scatterplot(
    data=df, x="petal_length", y="petal_width",
    hue="species",
    palette=["#FF6B8A", "#7B9FD4", "#5DBD8A"],
    ax=axes[1, 1]
)
axes[1, 1].set_title("꽃잎 길이 vs 꽃잎 너비")
axes[1, 1].set_xlabel("꽃잎 길이 (cm)")
axes[1, 1].set_ylabel("꽃잎 너비 (cm)")

plt.tight_layout()
plt.show()

💡 히트맵 읽는 법

  • 값이 1에 가까울수록 → 두 값이 함께 커지는 경향 (양의 상관관계)
  • 값이 -1에 가까울수록 → 한 값이 커지면 다른 값은 작아지는 경향 (음의 상관관계)
  • 값이 0에 가까울수록 → 두 값 사이에 관계가 거의 없음 ❓ 생각해보기: 히트맵에서 petal_length와 petal_width의 상관계수가 높게 나오죠? 실제 산점도 (4번 그래프)와 비교해보세요. 일치하나요?

STEP 6. 도전 과제 🔥

아래 문제를 직접 코드로 풀어보세요!

📌 도전 1 — 꽃받침 넓이 계산하기

꽃받침의 넓이를 sepal_length × sepal_width로 근사해서 새 컬럼 sepal_area를 만들어보세요.

# 여기에 코드를 작성해보세요
df["sepal_area"] = ___  # sepal_length × sepal_width
print(df[["species", "sepal_area"]].groupby("species").mean().round(2))

📌 도전 2 — 히스토그램 그리기

꽃잎 길이(petal_length)의 전체 분포를 히스토그램으로 그려보세요.

import matplotlib.pyplot as plt
import seaborn as sns

df = sns.load_dataset("iris")

# 힌트: sns.histplot() 또는 plt.hist() 사용
# bins=20 으로 막대 개수를 설정해보세요

📌 도전 3 (심화) — pairplot 그리기

Seaborn의 pairplot은 모든 수치 컬럼 쌍을 한 번에 산점도로 그려줘요. 한 줄로 그려보세요!

import seaborn as sns

df = sns.load_dataset("iris")

# 한 줄로 완성해보세요!
sns.pairplot(___, hue=___)

오늘 배운 것 정리

단계라이브러리한 일
STEP 1Pandas데이터 불러오기 & 기본 탐색
STEP 2NumPy품종별 통계 직접 계산
STEP 3Pandasgroupby로 집계 & 필터링
STEP 4Matplotlib막대 그래프, 산점도 직접 그리기
STEP 5Seaborn박스플롯, 히트맵, 바이올린 플롯
STEP 6전체도전 과제

4가지 라이브러리를 모두 써서 하나의 데이터셋을 처음부터 끝까지 분석했어요. 데이터 분석의 기본 흐름인 불러오기 → 탐색 → 통계 → 시각화 를 직접 경험한 거예요!

관련 포스트

댓글

방명록을 남겨주세요