Day 2 — 데이터를 그림으로 보여주기¶
2일 데이터분석 특강 (2일차) · 복습 + groupby + Matplotlib + 미니 프로젝트
| 오늘 해볼 것 | 도구 |
|---|---|
| 1. Day 1 복습 퀴즈 (5문제) | NumPy · Pandas |
| 2. 그룹별로 묶어 계산하기 | groupby |
| 3. 그래프 그리기 (선·막대·히스토그램) | Matplotlib |
| 4. 미니 프로젝트: 급식 만족도 분석 | 전부 다! |
| 5. 면접 답변 완성 (30초 스피치) |
시작 전:
파일 → Drive에 사본 저장잊지 마세요!
0. 준비 — 아래 두 셀을 먼저 실행하세요¶
첫 번째 셀은 그래프에서 한글이 깨지지 않도록 설정하는 준비 셀입니다. 내용을 이해할 필요 없이 실행만 하면 됩니다.
# [준비 1] 그래프 한글 설정 — 그냥 실행하세요 (코랩에서는 10초쯤 걸려요)
import sys, platform
import matplotlib
try:
if "google.colab" in sys.modules: # 구글 코랩이라면: 한글 폰트 설치
import subprocess
subprocess.run([sys.executable, "-m", "pip", "install", "-q", "koreanize-matplotlib"],
check=True)
import koreanize_matplotlib # 불러오면 끝! (런타임 재시작 필요 없음)
else: # 선생님 컴퓨터(맥/윈도우)라면: 기본 한글 폰트 사용
fam = {"Darwin": "AppleGothic", "Windows": "Malgun Gothic"}.get(platform.system())
if fam:
matplotlib.rcParams["font.family"] = fam
matplotlib.rcParams["axes.unicode_minus"] = False
print("한글 그래프 준비 완료!")
except Exception as e:
print("폰트 준비 실패 — 그래프 제목·라벨을 영어로 쓰면 됩니다. (선생님께 알려주세요)", e)
# [준비 2] 도구 3총사 불러오기 + Day 1의 우리 반 데이터 다시 만들기
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({
"이름": ["민준", "서연", "도윤", "하은", "시우", "지우", "주원", "서준", "지아", "예준",
"하린", "은우", "수아", "지호", "아린", "선우", "유나", "정우", "소율", "시윤"],
"반": ["1반", "1반", "1반", "1반", "1반", "1반", "1반", "1반", "1반", "1반",
"2반", "2반", "2반", "2반", "2반", "2반", "2반", "2반", "2반", "2반"],
"좋아하는과목": ["체육", "수학", "체육", "음악", "과학", "체육", "수학", "미술", "국어", "체육",
"음악", "과학", "체육", "수학", "음악", "체육", "국어", "과학", "미술", "체육"],
"국어": [85, 92, 70, 88, 76, 95, 64, 81, 90, 73,
78, 84, 66, 91, 87, 59, 94, 72, 80, 68],
"수학": [78, 95, 62, 84, 90, 71, 88, 55, 79, 92,
83, 96, 58, 89, 74, 67, 85, 91, 63, 77],
"게임시간": [10, 3, 14, 6, 4, 8, 5, 15, 7, 3,
6, 2, 13, 4, 9, 12, 3, 5, 11, 8],
})
print("데이터 준비 완료!", len(df), "명")
df.head(3)
1. 복습 퀴즈 — Day 1 내용 점검 (5문제, 10분)¶
막히면 각 문제의 힌트와 아래 '정답 보기'를 참고하세요.
# 퀴즈 1: [80, 95, 70, 100, 85]로 NumPy 배열 arr를 만들고 평균을 출력하세요.
# 힌트: arr = np.array([ ... ]) → arr.mean()
# 퀴즈 2: arr에서 90점 이상만 골라내 보세요.
# 힌트: arr[arr >= ??]
# 퀴즈 3: df에서 "게임시간" 열의 평균을 출력하세요.
# 힌트: df["??"].mean()
# 퀴즈 4: 수학 80점 이상인 학생만 골라 보세요.
# 힌트: df[df["??"] >= 80]
# 퀴즈 5: 국어 점수가 높은 순으로 정렬해서 상위 3명만 보세요.
# 힌트: df.sort_values("??", ascending=False).head(??)
정답 보기 (퀴즈 1~5)
# 퀴즈 1
arr = np.array([80, 95, 70, 100, 85])
print(arr.mean())
# 퀴즈 2
print(arr[arr >= 90])
# 퀴즈 3
print(df["게임시간"].mean())
# 퀴즈 4
df[df["수학"] >= 80]
# 퀴즈 5
df.sort_values("국어", ascending=False).head(3)
2. groupby — 그룹별 집계(aggregation)¶
전체 평균이 아니라 그룹별 통계가 필요할 때 씁니다. "그룹으로 묶고(group) → 그룹마다 계산한다(aggregate)" — 두 단계가 한 줄에 들어 있어요.
df.groupby(묶을기준)[계산할열].mean() — "○○별 △△ 평균" 이라고 읽으면 구조가 잡힙니다.
# 반별 수학 평균 — "반별 수학 평균"이라고 소리 내어 읽으면서 실행!
df.groupby("반")["수학"].mean()
# 값 개수 세기: 좋아하는 과목별로 몇 명?
df["좋아하는과목"].value_counts()
# TODO(2-1): 반별 "국어" 평균을 구해 보세요. 어느 반이 더 높나요?
# 힌트: df.groupby("반")["??"].mean()
# 여러 과목을 한 번에 보고 싶다면? 열 이름을 [리스트]로 주면 끝!
df.groupby("반")[["국어", "수학"]].mean() # 대괄호가 두 겹인 것에 주목!
# 심화 한 스푼: 평균만이 아니라 여러 통계를 동시에 — agg(집계 함수 목록)
df.groupby("반")["수학"].agg(["mean", "max", "min", "std"]).round(2)
# TODO(2-2): "좋아하는과목"별 수학 평균을 구해 보세요.
# 수학을 좋아하는 친구들이 정말 수학 점수도 높을까요? # 힌트: df.groupby("??")["수학"].mean()
정답 보기 (2-1 ~ 2-2)
# 2-1
df.groupby("반")["국어"].mean()
# 2-2
df.groupby("좋아하는과목")["수학"].mean()
연습 더하기 — groupby (선택: 수업에서 건너뛰면 자습으로!)¶
# G-1: 반별 "게임시간" 평균을 구하세요. 어느 반이 게임을 더 할까요?
# 힌트: df.groupby("반")["??"].mean()
# G-2: "좋아하는과목"별 게임시간 평균 — 체육을 좋아하는 친구들은 게임도 많이 할까요? # 힌트: df.groupby("??")["게임시간"].mean()
정답 보기 (G-1 ~ G-2)
df.groupby("반")["게임시간"].mean() # G-1 (1반 7.5 / 2반 7.3 — 비슷!)
df.groupby("좋아하는과목")["게임시간"].mean().round(2) # G-2 (체육파의 게임시간이 압도적)
G-2 해석: 관계가 보이죠? 하지만 이것도 "체육을 좋아해서 게임을 많이 한다"는 인과의 증거는 아닙니다.
3. Matplotlib — 그래프 3총사 숫자 표는 안 읽혀도, 그림은 한눈에 보여요. 상황에 맞는 그래프를 고르는 게 실력!¶
| 그래프 | 언제 쓰나 | 예시 |
|---|---|---|
선 plt.plot |
시간에 따른 변화 | 일주일 게임 시간 변화 |
막대 plt.bar |
항목끼리 비교 | 반별 평균 비교 |
히스토그램 plt.hist |
점수의 분포 | 수학 점수가 어디에 몰려 있나 |
규칙 하나: 그래프에는 반드시 제목과 축 이름을 붙입니다. (없으면 무슨 그림인지 아무도 몰라요!)
# 선 그래프: 일주일 게임 시간의 "변화"
days = ["월", "화", "수", "목", "금", "토", "일"]
game = [1, 1, 2, 1, 3, 5, 4] # 하루 게임 시간
plt.plot(days, game, marker="o") # marker="o" : 점 찍기
plt.title("일주일 게임 시간 변화") # 제목
plt.xlabel("요일") # 가로축 이름
plt.ylabel("시간") # 세로축 이름
plt.show()
# TODO(3-1): 일주일 공부 시간 study = [2, 3, 2, 3, 1, 4, 5] 를 선 그래프로 그려 보세요.
# 제목과 축 이름도 꼭 붙이세요!
# 힌트: plt.plot(days, study, marker="o") → plt.title("...") → plt.xlabel/ylabel → plt.show()
# 선 "두 개"를 한 그래프에! — label을 달고 legend(범례)를 부르면 비교 완성
study = [2, 3, 2, 3, 1, 4, 5]
plt.plot(days, game, marker="o", label="게임")
plt.plot(days, study, marker="s", label="공부")
plt.title("게임 시간 vs 공부 시간")
plt.xlabel("요일")
plt.ylabel("시간")
plt.legend() # label들을 모아 범례 상자를 만들어 줘요
plt.show()
# 막대 그래프: 반별 수학 평균 "비교" — 아까 groupby 결과를 그대로 그림으로!
avg = df.groupby("반")["수학"].mean()
plt.bar(avg.index, avg.values) # index(반 이름)를 가로축, values(평균)를 세로축에
plt.title("반별 수학 평균")
plt.ylabel("점수")
plt.show()
# TODO(3-2): 좋아하는 과목별 인원수(value_counts)를 막대 그래프로 그려 보세요.
# 힌트: cnt = df["좋아하는과목"].value_counts() → plt.bar(cnt.index, cnt.values)
# 제목·축 이름도 잊지 마세요!
# 히스토그램: 수학 점수의 "분포" — 점수가 어느 구간에 몰려 있을까?
plt.hist(df["수학"], bins=5, edgecolor="black") # bins: 구간을 몇 개로 나눌지
plt.title("수학 점수 분포")
plt.xlabel("점수")
plt.ylabel("학생 수")
plt.show()
# TODO(3-3): 국어 점수의 히스토그램을 그려 보세요.
# 힌트: plt.hist(df["??"], bins=5, edgecolor="black") + 제목·축 이름
# 한 줄 꿀팁: Pandas 표에서 바로 그래프 그리기 (plot 안에 kind로 종류 지정)
df.groupby("반")["국어"].mean().plot(kind="bar", title="반별 국어 평균")
plt.show()
# 꿀팁 응용: 여러 열을 한꺼번에 → "그룹 막대"가 자동으로! (범례까지 공짜)
df.groupby("반")[["국어", "수학"]].mean().plot(kind="bar", title="반별 국어·수학 평균 비교")
plt.ylabel("점수")
plt.show()
정답 보기 (3-1 ~ 3-3)
# 3-1
study = [2, 3, 2, 3, 1, 4, 5]
plt.plot(days, study, marker="o")
plt.title("일주일 공부 시간 변화")
plt.xlabel("요일")
plt.ylabel("시간")
plt.show()
# 3-2
cnt = df["좋아하는과목"].value_counts()
plt.bar(cnt.index, cnt.values)
plt.title("좋아하는 과목별 인원수")
plt.ylabel("명")
plt.show()
# 3-3
plt.hist(df["국어"], bins=5, edgecolor="black")
plt.title("국어 점수 분포")
plt.xlabel("점수")
plt.ylabel("학생 수")
plt.show()
연습 더하기 — 그래프 (선택: 수업에서 건너뛰면 자습으로!)¶
이번엔 우리 반 데이터를 잠시 벗어나, 실제 세상 데이터를 그려 봅시다.
# 서울의 월별 평균 기온 (대략적인 값) — "변화"니까 선 그래프!
months = ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"]
temp = [-2, 0, 6, 13, 18, 23, 26, 27, 22, 15, 7, 0]
plt.plot(months, temp, marker="o", color="tomato") # color로 색도 지정할 수 있어요
plt.title("서울 월별 평균 기온")
plt.xlabel("월")
plt.ylabel("기온(°C)")
plt.show()
# V-1: 서울의 월별 강수량(대략) rain = [20, 25, 45, 75, 105, 130, 390, 340, 150, 50, 50, 20]
# 을 막대 그래프로 그리세요. 어느 계절에 비가 집중되나요?
# 힌트: plt.bar(months, rain) + 제목·축 이름 — 색을 바꾸고 싶으면 color="steelblue"
# V-2: 수학 점수 히스토그램을 bins=10으로 다시 그려 보세요.
# 아까 bins=5와 비교하면 어떤 게 분포를 더 잘 보여주나요? (정답은 없어요 — 관찰!)
# 힌트: plt.hist(df["수학"], bins=??, edgecolor="black")
정답 보기 (V-1 ~ V-2)
# V-1 — 7~8월(여름 장마)에 강수량이 집중!
rain = [20, 25, 45, 75, 105, 130, 390, 340, 150, 50, 50, 20]
plt.bar(months, rain, color="steelblue")
plt.title("서울 월별 강수량")
plt.xlabel("월")
plt.ylabel("강수량(mm)")
plt.show()
# V-2 — bins가 크면 잘게 보이지만, 데이터가 20개뿐이라 오히려 들쭉날쭉해 보일 수 있어요.
plt.hist(df["수학"], bins=10, edgecolor="black")
plt.show()
같은 데이터라도 bins(구간 개수)에 따라 인상이 달라진다 — 그래프를 볼 때 항상 조심할 점입니다!
4. 미니 프로젝트 — 급식 만족도 분석가 되기 (15분)¶
학교 급식 3주치 데이터가 왔어요. 데이터 분석가가 되어 두 가지 질문에 답해 봅시다.
질문 1: 만족도 4점 이상 "인기 메뉴"는 무엇일까?
질문 2: 무슨 요일 급식이 가장 만족스러울까?
지금까지 배운 것만으로 충분히 풀 수 있어요. 이번엔 처음부터 끝까지 스스로! (이 프로젝트가 끝나면, 면접에서 말할 "나의 데이터분석 경험"이 하나 생깁니다.)
# 급식 데이터 (3주치, 15일) — 실행해서 데이터를 만들어 주세요
meal = pd.DataFrame({
"메뉴": ["치킨마요덮밥", "비빔밥", "돈까스", "미역국정식", "떡볶이",
"카레라이스", "제육볶음", "생선구이", "스파게티", "김치찌개",
"피자", "불고기", "콩자반정식", "냉면", "갈비탕"],
"요일": ["월", "화", "수", "목", "금",
"월", "화", "수", "목", "금",
"월", "화", "수", "목", "금"],
"만족도": [5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 5, 4, 1, 4, 4], # 5점 만점
"잔반량": [5, 40, 18, 62, 8, 35, 20, 58, 10, 30, 6, 15, 80, 22, 18], # 1인당 평균(g)
})
meal
# 프로젝트 1단계: 데이터 파악 — 요약 통계(describe)를 확인해 보세요.
# 만족도 평균은 몇 점인가요?
# 힌트: meal.describe()
# 프로젝트 2단계: 만족도 4점 이상인 "인기 메뉴"만 골라 보세요.
# 힌트: meal[meal["??"] >= ??]
# 프로젝트 3단계: 요일별 만족도 평균을 구해 보세요. 최고의 요일은? 최악의 요일은?
# 힌트: meal.groupby("??")["만족도"].mean()
# 프로젝트 4단계 (피날레): 3단계 결과를 막대 그래프로! 제목은 "요일별 급식 만족도"
# 힌트: avg = meal.groupby(...)... → plt.bar(avg.index, avg.values) → plt.title(...)
정답 보기 (프로젝트 1~4단계)
# 1단계
meal.describe()
# 2단계
meal[meal["만족도"] >= 4]
# 3단계
meal.groupby("요일")["만족도"].mean()
# 4단계
avg = meal.groupby("요일")["만족도"].mean()
plt.bar(avg.index, avg.values)
plt.title("요일별 급식 만족도")
plt.ylabel("만족도(점)")
plt.show()
# (보너스 한 줄) 요일을 월~금 순서로 보고 싶다면:
# avg.reindex(["월", "화", "수", "목", "금"])
5. 면접 답변 완성 — "데이터분석 경험을 말해 보세요"¶
공식: 상황 → 행동 → 배움 (30초)
"저는 파이썬으로 급식 만족도 데이터를 분석해 본 경험이 있습니다. (상황)
Pandas로 만족도 4점 이상인 인기 메뉴를 골라내고, 요일별 평균 만족도를 구해서 Matplotlib 막대 그래프로 그렸습니다. (행동)
그 결과 수요일 급식의 만족도가 가장 낮다는 것을 발견했고, 감이 아니라 데이터로 근거를 들어 말하는 방법을 배웠습니다. (배움)"
이제 아래 빈칸을 자기 말로 채워서 소리 내어 연습하세요. (그대로 외우지 말고, 진짜 기억에 남는 것으로!)
- 저는 파이썬으로 ________ 를 분석해 봤습니다.
- ________ 라이브러리로 ________ 를 하고, ________ 그래프를 그렸습니다.
- 그 결과 ________ 를 알게 되었고, ________ 을 배웠습니다.
용어 4개: DataFrame(표 자료구조) · groupby(그룹별 집계) · 시각화 · 상관계수
한 단계 위의 답변: "산점도로 두 변수의 관계를 확인하고 상관계수까지 계산해 봤는데, 상관관계가 곧 인과관계는 아니라는 점이 가장 기억에 남습니다."
한 걸음 더 — 그래프 실전 꾸미기 (심화)¶
진짜 리포트처럼! 정렬해서 그리기와 x축 글자 기울이기만 알면 그래프가 확 달라져요.
# 메뉴별 만족도 "랭킹 차트" — 정렬(sort_values) → 막대, 그리고 글자 겹침 방지!
top = meal.sort_values("만족도", ascending=False)
plt.bar(top["메뉴"], top["만족도"])
plt.title("메뉴별 만족도 랭킹")
plt.ylabel("만족도(점)")
plt.xticks(rotation=45) # x축 글자를 45도 기울이기 — 이름이 길 때 필수 꿀팁!
plt.show()
# TODO(심화-1): 우리 반 데이터(df)로 "수학 점수 상위 5명"의 이름-점수 막대 그래프를 그려 보세요.
# (정렬 → head(5) → 막대, 3단 콤보!)
# 힌트: top5 = df.sort_values("??", ascending=False).head(??)
# plt.bar(top5["이름"], top5["수학"]) + 제목·축 이름
정답 보기 (심화-1)
top5 = df.sort_values("수학", ascending=False).head(5)
plt.bar(top5["이름"], top5["수학"])
plt.title("수학 점수 TOP 5")
plt.ylabel("점수")
plt.show()
보너스 — 산점도, 상관계수, 그래프 저장¶
**산점도(scatter)**는 두 변수의 관계를 보는 그래프이고, 그 관계의 세기를 숫자로 요약한 것이 상관계수입니다. 질문: "만족도가 높으면 잔반이 줄어들까?" — 그림과 숫자, 두 가지로 확인해 봅시다.
plt.scatter(meal["만족도"], meal["잔반량"])
plt.title("만족도와 잔반량의 관계")
plt.xlabel("만족도(점)")
plt.ylabel("잔반량(g)")
plt.show()
# 오른쪽으로 갈수록(만족도↑) 점이 아래로(잔반↓) — "음(-)의 상관관계"
# 관계의 방향과 세기를 숫자 하나로 요약한 것이 상관계수 (-1 ~ +1)
print("상관계수:", meal["만족도"].corr(meal["잔반량"]).round(2))
# -1에 가까움: 반대로 움직임 / +1에 가까움: 같이 움직임 / 0 근처: 직선 관계 없음
# TODO(보너스): 우리 반 데이터(df)로 "게임시간"과 "수학" 점수의 산점도를 그리고,
# 상관계수도 출력해 보세요. 둘 사이에 관계가 보이나요?
# 상관계수가 아무리 강해도 "게임 때문에 점수가 낮다"고 단정할 수는 없어요! (상관 ≠ 인과)
# 힌트: plt.scatter(df["게임시간"], df["수학"]) + 제목·축 이름
# 상관계수: df["게임시간"].corr(df["수학"])
# 내가 만든 그래프를 이미지 파일로 저장하기 (자소서·발표 자료에 쓸 수 있어요!)
avg = meal.groupby("요일")["만족도"].mean()
plt.bar(avg.index, avg.values)
plt.title("요일별 급식 만족도")
plt.ylabel("만족도(점)")
plt.savefig("나의첫그래프.png", dpi=150, bbox_inches="tight")
plt.show()
print("저장 완료 — 왼쪽 사이드바의 파일 아이콘에서 다운로드할 수 있습니다.")
정답 보기 (보너스)
plt.scatter(df["게임시간"], df["수학"])
plt.title("게임시간과 수학 점수의 관계")
plt.xlabel("게임시간(시간/주)")
plt.ylabel("수학 점수")
plt.show()
print("상관계수:", df["게임시간"].corr(df["수학"]).round(2))
출력된 상관계수를 직접 읽어보세요 — 이 수치를 면접에서 인용할 수 있습니다.
2일 과정은 여기까지입니다. 파일 → 다운로드 → .ipynb로 노트북을 보관하고,
만든 그래프 이미지도 함께 내려받아 두세요. (자기소개서·면접 자료로 활용할 수 있습니다)