Day 1 — 데이터를 숫자로 다루기¶
2일 데이터분석 특강 (1일차) · NumPy & Pandas
| 오늘 해볼 것 | 도구 |
|---|---|
| 1. 코랩(Colab) 사용법 익히기 | Google Colab |
| 2. 배열 기반 수치 계산 — 벡터 연산 | NumPy |
| 3. 표(DataFrame) 데이터 다루기 | Pandas |
| 4. 오늘 배운 것을 "말로" 정리하기 | 면접 대비 |
데이터분석이란? 질문하기 → 데이터 모으기 → 계산하기 → 그림 그리기 → 해석하기. 유튜브 추천, 게임 매칭, 급식 메뉴 선정… 전부 데이터분석의 결과예요. 오늘부터 우리가 직접 해봅니다!
0. 시작하기 전에 — 코랩 사용법 딱 3가지¶
- 내 것으로 만들기: 왼쪽 위 메뉴
파일 → Drive에 사본 저장— 이걸 먼저 해야 내 코드가 저장돼요! - 셀 실행: 셀을 클릭하고
Shift + Enter(또는 셀 왼쪽 ▶ 버튼) - 위에서부터 순서대로 실행하세요. 중간부터 실행하면 에러가 날 수 있어요.
# 파이썬 3분 워밍업 — Shift + Enter 로 실행해 보세요!
name = "데이터 분석가"
print("안녕하세요,", name, "님!")
scores = [85, 90, 70] # 리스트: 값을 여러 개 담는 상자
print("첫 번째 점수:", scores[0]) # 번호는 0부터!
print("점수 개수:", len(scores))
# TODO(워밍업): 좋아하는 과목 3개를 리스트로 만들고, 첫 번째 과목을 출력해 보세요.
# 힌트: subjects = ["??", "??", "??"] → print(subjects[0])
1. NumPy — 배열 기반 수치 계산 라이브러리¶
NumPy는 Numerical Python(수치 계산용 파이썬)의 줄임말로, 파이썬 숫자 계산의 가장 기본이 되는 라이브러리입니다.
- 핵심 아이디어: 숫자들을 **배열(array)**이라는 전용 자료구조에 담고, 배열 전체에 연산을 한 번에 적용한다 — 이것을 벡터 연산이라고 합니다.
- 반복문으로 하나씩 처리하는 것보다 훨씬 빠르고 간결해서, 데이터분석·과학 계산·인공지능의 수치 계산은 사실상 전부 NumPy 위에서(또는 NumPy 방식으로) 돌아갑니다.
- 잠시 후 배울 Pandas도 내부적으로 NumPy 배열에 데이터를 저장합니다. 지금 배우는 것이 오늘 전체의 기반이에요.
import numpy as np # 표준 약어 np — 전 세계 데이터 분석 코드의 관례
scores_list = [80, 95, 70, 100, 85] # 파이썬 리스트
scores = np.array([80, 95, 70, 100, 85]) # NumPy 배열
print("리스트 * 2 :", scores_list * 2) # 리스트는 통째로 두 번 반복될 뿐
print("배열 * 2 :", scores * 2) # 배열은 원소 하나하나를 계산 (벡터 연산)
# 전원 5점 보정 — 반복문 없이 한 줄
print("보정 전:", scores)
print("보정 후:", scores + 5) # 숫자 하나(5)가 배열 전체에 퍼져 적용됨 = 브로드캐스팅(broadcasting)
왜 NumPy는 빠를까? — 배열의 두 가지 규칙¶
같은 계산인데 NumPy가 훨씬 빠른 이유는, 배열이 리스트와 구조 자체가 다르기 때문입니다.
| 파이썬 리스트 | NumPy 배열 | |
|---|---|---|
| 담는 값 | 아무거나 섞어서 (숫자, 글자, 리스트…) | 같은 자료형(dtype)만 |
| 저장 방식 | 값들이 메모리 여기저기에 흩어짐 | 연속된 메모리에 차곡차곡 |
| 계산 주체 | 파이썬이 하나씩 처리 | C 언어로 만든 엔진이 한꺼번에 처리 |
비유하면 — 리스트는 잡동사니 상자(하나씩 꺼내 확인해야 함), 배열은 계란판(같은 크기 칸이 연속으로 붙어 있어 통째로 다룰 수 있음)입니다.
# 배열의 정체를 직접 확인해 봅시다
print(type(scores)) # numpy.ndarray — "n차원 배열(n-dimensional array)"이라는 뜻
print(scores.dtype) # 이 배열이 담는 자료형 (예: int64 = 64비트 정수)
print(scores.shape) # 모양 — (5,)는 1차원에 원소 5개. 나중에 2차원 (행, 열)로 확장됩니다
# TODO(1-1): 수학 점수 [72, 88, 95, 60, 79]를 NumPy 배열 math로 만들고,
# 전원 3점을 올린 결과를 출력해 보세요.
# 힌트: math = np.array([ ... ]) → print(math + 3)
통계 함수 — 평균 · 최대 · 최소 · 합계 · 표준편차¶
데이터분석의 첫걸음은 **요약(기술통계)**입니다. 점수 30개를 다 읽는 대신 대표값 몇 개로 전체를 파악해요. **표준편차(std)**는 값들이 평균 주변에 얼마나 흩어져 있는지를 나타냅니다 — 작을수록 고르게 몰려 있다는 뜻.
print("평균:", scores.mean())
print("최고:", scores.max())
print("최저:", scores.min())
print("합계:", scores.sum())
print("표준편차:", scores.std().round(2)) # 평균 86점 주변으로 얼마나 퍼져 있나
# TODO(1-2): 우리 모둠 5명의 키 [168, 172, 155, 180, 163]으로 배열 heights를 만들고,
# 평균 키와 가장 큰 키를 출력해 보세요.
# 힌트: heights = np.array([ ... ]) → heights.mean() 과 heights.max()
조건으로 골라내기 — 불린 마스킹(boolean masking) 배열[조건] 형태로 쓰면 조건이 True인 원소만 남습니다. 데이터분석에서 가장 많이 쓰는 핵심 기법이라 정식 명칭까지 알아둘 가치가 있어요.¶
(원리: scores >= 90 자체가 [False, True, ...] 같은 True/False 배열을 만들고, 그걸 마스크(가림막)로 씁니다)
print("첫 번째 점수:", scores[0]) # 인덱싱: 위치 번호로 접근 (0부터 시작)
print("마지막 점수:", scores[-1]) # 음수 인덱스: 뒤에서부터
print("1~3번 점수:", scores[1:4]) # 슬라이싱: [시작:끝] — 끝 번호 직전까지
print("조건 배열:", scores >= 90) # True/False로 이루어진 배열이 먼저 만들어지고
print("90점 이상만:", scores[scores >= 90]) # True인 위치의 값만 남는다 = 불린 마스킹
# TODO(1-3): scores에서 80점 이상인 점수만 골라 출력하고, 몇 개인지도 출력해 보세요.
# 힌트: high = scores[scores >= ??] → print(high) → print(len(high))
# 골라내기 + 통계를 "조합"하면 진짜 분석이 시작돼요!
print("90점 이상은 몇 명?", (scores >= 90).sum()) # 조건 만족 개수 세기
print("80점 이상만의 평균:", scores[scores >= 80].mean()) # 골라낸 다음 → 평균
# TODO(1-4): heights에서 160cm 이상인 키만 골라, "그들의 평균 키"를 출력해 보세요. (조합 문제!)
# 힌트: heights[heights >= ??].mean() ← 골라내기와 평균을 이어 붙이면 됩니다
정답 보기 (1-1 ~ 1-4) — 막혔을 때만 여세요!
# 1-1
math = np.array([72, 88, 95, 60, 79])
print(math + 3)
# 1-2
heights = np.array([168, 172, 155, 180, 163])
print("평균 키:", heights.mean())
print("최대 키:", heights.max())
# 1-3
high = scores[scores >= 80]
print(high)
print(len(high), "개")
# 1-4
print(heights[heights >= 160].mean())
NumPy는 어디에 쓰일까? — 이미지도 결국 숫자 배열¶
- 인공지능(AI): 흑백 사진은 밝기 숫자(0~255)가 가로×세로로 늘어선 2차원 배열이고, 컬러 사진은 여기에 빨강·초록·파랑 층이 더해진 3차원 배열입니다. AI가 사진을 "본다"는 것은 결국 이 배열을 계산한다는 뜻이에요.
- 과학·공학: 날씨 예보 시뮬레이션, 게임 물리 엔진의 수많은 좌표 계산.
- 데이터 생태계: Pandas(표) · Matplotlib(그래프) · scikit-learn(머신러닝)이 전부 NumPy 배열 위에서 동작합니다.
면접에서 "NumPy가 왜 중요한가요?" → "파이썬 데이터 생태계 전체의 기반 라이브러리이고, 이미지 같은 데이터도 결국 숫자 배열이라 AI 계산의 출발점이기 때문입니다."
연습 더하기 — NumPy (선택: 수업에서 건너뛰면 자습으로!)¶
# 배열끼리도 연산됩니다: 중간고사 vs 기말고사 (같은 위치끼리 계산)
mid = np.array([70, 85, 60, 90, 75]) # 중간고사
fin = np.array([82, 88, 71, 85, 90]) # 기말고사
print("향상도:", fin - mid) # 누가 가장 많이 올랐을까?
print("두 시험 평균:", (mid + fin) / 2)
# N-1: 일주일 걸음 수 [8500, 12000, 6200, 15300, 9800, 4500, 11000]로 배열을 만들고,
# 하루 평균 걸음 수와, "만 보(10000) 이상" 걸은 날이 며칠인지 구하세요.
# 힌트: steps.mean() / (steps >= 10000).sum()
# N-2: 위의 mid, fin으로 — 가장 큰 향상도는 몇 점? 10점 이상 오른 사람은 몇 명?
# 힌트: gain = fin - mid → gain.max() / (gain >= 10).sum()
정답 보기 (N-1 ~ N-2)
# N-1
steps = np.array([8500, 12000, 6200, 15300, 9800, 4500, 11000])
print("평균:", steps.mean().round(1)) # 9614.3
print("만 보 이상:", (steps >= 10000).sum()) # 3일
# N-2
gain = fin - mid
print("최대 향상:", gain.max()) # 15
print("10점 이상:", (gain >= 10).sum(), "명") # 3명
2. Pandas — 표 형태 데이터를 다루는 라이브러리¶
- 행(row)과 열(column)로 이루어진 표 하나를 DataFrame이라고 합니다. 엑셀 시트를 코드로 조작한다고 생각하면 정확해요.
- 표에서 열 하나만 떼어낸 것은 Series라고 부릅니다. DataFrame과 Series — 이 두 용어는 면접에서 그대로 쓸 수 있어야 해요.
import pandas as pd # 표준 약어 pd
# 우리 반 성적 데이터 (가상의 20명)
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],
})
df # 셀 마지막 줄에 변수 이름만 쓰면 표가 예쁘게 출력돼요
df.head() # 앞 5행만 살짝 보기 — 데이터를 받으면 제일 먼저 하는 일!
df.info() # 행·열 개수, 각 열의 자료형(dtype), 누락값 여부까지 한 번에 점검
df.describe() # 숫자 열의 기술통계 요약 — mean(평균), std(표준편차), 50%(중앙값)에 주목!
# TODO(2-1): 표의 앞에서 3행만 출력해 보세요.
# 힌트: df.head(??)
열 선택과 조건 필터 — "수학 90점 이상만 보여줘"¶
NumPy에서 배운 불린 마스킹이 표에서도 그대로 통합니다.
math_col = df["수학"] # 열 하나를 떼어내면 Series
print(type(math_col)) # <class 'pandas.core.series.Series'>
print(math_col.head())
print("수학 평균:", math_col.mean(), "/ 표준편차:", math_col.std().round(2))
# 수학 90점 이상인 행만 남기기 (읽는 법: "df에서, 수학이 90 이상인 행만")
df[df["수학"] >= 90]
# TODO(2-2): 국어 90점 이상인 학생만 골라 출력해 보세요.
# 힌트: df[df["국어"] >= ??]
# 문자열 조건도 가능: 1반 학생만
df[df["반"] == "1반"] # = 는 대입(넣기), == 는 비교 연산자(같은지 묻기) — 완전히 다른 기호!
# TODO(2-3): 2반 학생만 골라내고, 몇 명인지 len()으로 세어 보세요.
# 힌트: ban2 = df[df["반"] == "??"] → len(ban2)
정렬과 새 열 만들기 — "1등이 누구야?"¶
# 수학 점수 높은 순으로 정렬 (ascending=False → 내림차순)
df.sort_values("수학", ascending=False).head()
# 새 열 만들기: 총점 = 국어 + 수학
df["총점"] = df["국어"] + df["수학"]
df.head()
# TODO(2-4): 총점이 높은 순으로 정렬해서, 1등이 누구인지 확인해 보세요.
# 힌트: df.sort_values("??", ascending=False).head(1)
# 표를 CSV 파일로 저장했다가, 다시 읽어오기
# (실전 데이터분석은 보통 남이 만든 CSV 파일을 read_csv로 읽으면서 시작해요)
df.to_csv("우리반_성적.csv", index=False)
df2 = pd.read_csv("우리반_성적.csv")
print("파일에서 다시 읽었어요! 행 개수:", len(df2))
df2.head(3)
정답 보기 (2-1 ~ 2-4)
# 2-1
df.head(3)
# 2-2
df[df["국어"] >= 90]
# 2-3
ban2 = df[df["반"] == "2반"]
print(len(ban2), "명")
ban2
# 2-4
df.sort_values("총점", ascending=False).head(1)
연습 더하기 — Pandas (선택: 수업에서 건너뛰면 자습으로!)¶
# 필요한 열만 골라 보기 — 열 이름을 [리스트]로 (대괄호가 두 겹!)
print(df[["이름", "수학"]].head(3))
# 앞이 head라면 뒤는? — 끝에서 3행
df.tail(3)
# P-1: "이름"과 "게임시간" 두 열만 골라 앞 5행을 확인하세요.
# 힌트: df[["??", "??"]].head() — 대괄호 두 겹!
# P-2: 수학 최고점과 최저점을 각각 출력하세요. 점수 차이(최고-최저)도!
# 힌트: df["수학"].max() / df["수학"].min() — 차이는 빼기
# P-3 (조합): 게임시간 상위 3명의 "이름"과 "게임시간"만 보기.
# (정렬 → 상위 3 → 열 고르기, 3단 조합!)
# 힌트: df.sort_values("??", ascending=False).head(3)[["이름", "게임시간"]]
정답 보기 (P-1 ~ P-3)
df[["이름", "게임시간"]].head() # P-1
print(df["수학"].max(), df["수학"].min()) # P-2 (96 / 55 / 차이 41)
df.sort_values("게임시간", ascending=False).head(3)[["이름", "게임시간"]] # P-3 (서준·도윤·수아)
한 걸음 더 — 조건 "두 개"를 조합하기 (심화)¶
"수학도 잘하고 국어도 잘하는 학생"처럼 조건이 두 개라면? &(그리고)로 이어 붙이면 돼요.
규칙: 각 조건을 꼭 괄호로 감싸기!
(조건1) & (조건2)
# 국어 80점 이상 "그리고" 수학 80점 이상 — 둘 다 잘하는 학생!
df[(df["국어"] >= 80) & (df["수학"] >= 80)]
# 참고: "또는"은 | 기호를 써요. 예) 국어 90 이상 또는 수학 90 이상
# df[(df["국어"] >= 90) | (df["수학"] >= 90)]
# TODO(심화-1): 수학 90점 이상 "그리고" 게임시간 5시간 이하인 학생을 찾아보세요.
# (공부의 신인가, 시간 관리의 신인가!)
# 힌트: df[(df["수학"] >= ??) & (df["게임시간"] <= ??)] ← 괄호 조심!
# 조합 응용: "1반 학생들만의 수학 평균" — 골라내기 → 열 뽑기 → 평균, 3단 콤보!
print("1반 수학 평균:", df[df["반"] == "1반"]["수학"].mean())
# TODO(심화-2): 같은 방법으로 "2반 학생들만의 국어 평균"을 구해 보세요.
# 힌트: df[df["반"] == "??"]["국어"].mean()
심화 2 — 비율 계산 트릭, 그리고 NumPy와 Pandas의 관계¶
# 트릭: True는 1, False는 0으로 계산된다 → "조건의 평균 = 비율"
print("수학 90점 이상 비율:", (df["수학"] >= 90).mean()) # 0.25 → 전체의 25%
# NumPy 배열은 2차원(행렬)도 됩니다 — 사실 DataFrame은 2차원 배열에 이름표를 붙인 것!
matrix = np.array([[85, 78], [92, 95], [70, 62]]) # 3명 × 2과목
print("모양(행, 열):", matrix.shape)
print("과목별 평균:", matrix.mean(axis=0)) # axis=0: 세로(열) 방향으로 계산
# TODO(심화-3): "국어 80점 이상"인 학생의 비율을 구해 보세요.
# 힌트: (df["국어"] >= ??).mean()
다음 시간 예고: 심화-2에서 반마다 하나씩 평균을 구했습니다. 다음 수업에서는 이것을 한 줄로 모든 반에 대해 한꺼번에 처리하는
groupby(그룹별 집계)를 배웁니다.
정답 보기 (심화-1 ~ 심화-3)
# 심화-1
df[(df["수학"] >= 90) & (df["게임시간"] <= 5)]
# 심화-2
print("2반 국어 평균:", df[df["반"] == "2반"]["국어"].mean())
# 심화-3
print((df["국어"] >= 80).mean()) # 0.55 → 55%
3. 오늘 배운 것을 "말로" 정리하기 (면접 연습 1회차)¶
아래 세 문장의 빈칸을 채워서 소리 내어 말해 보세요. (이 문장들이 면접 답변의 재료가 됩니다!)
- "NumPy는 배열 전체에 ________ 연산을 한 번에 적용하는 수치 계산 라이브러리입니다. 저는 점수 배열의 평균과 표준편차를 구해 봤습니다."
- "Pandas는 ________ 이라는 표 형태 자료구조로 데이터를 다루는 라이브러리입니다. 저는 불린 마스킹으로 조건에 맞는 행만 추출해 봤습니다."
- "오늘 가장 인상적이었던 것은 ________ 입니다. 왜냐하면 ________ 때문입니다."
이 마크다운 셀을 더블클릭하면 직접 채워 넣을 수 있어요. 채운 뒤 Shift+Enter! 오늘의 용어 5개: 벡터 연산 · 브로드캐스팅 · 불린 마스킹 · DataFrame · Series
다음 수업까지 — 자습 안내¶
- 숙제 노트북(별도 링크): 섹션 A → B → C 순서로 하루 한 섹션(20~30분)씩 진행
- 자습 영상: 나도코딩 — 파이썬 데이터 분석 및 시각화 무료 강의 (유튜브)
- 이 노트북의 TODO를 정답을 보지 않고 다시 풀어보는 것도 좋은 복습 방법입니다.
- 다음 시간에는 오늘 만든 이 데이터를 그래프로 시각화합니다.
보너스 — 주사위 1000번: 몬테카를로 시뮬레이션 맛보기 난수를 대량으로 생성해 실험을 대신하는 것을 시뮬레이션이라고 합니다. 주사위 1000번, 코드로는 1줄이에요.¶
dice = np.random.randint(1, 7, size=1000) # 1 이상 7 미만의 정수 1000개
print("처음 20번:", dice[:20])
print("전체 평균:", dice.mean()) # 기댓값(이론상 평균)은 3.5 — 시행이 많을수록 가까워짐 (큰 수의 법칙)
# 각 눈이 몇 번씩 나왔는지 세기
pd.Series(dice).value_counts().sort_index()
# TODO(보너스): 동전 던지기! 0(앞면) 또는 1(뒷면)을 10000번 뽑아서 몇 번씩 나왔는지 세어 보세요.
# 힌트: coin = np.random.randint(0, 2, size=10000) → pd.Series(coin).value_counts()
정답 보기 (보너스)
coin = np.random.randint(0, 2, size=10000)
pd.Series(coin).value_counts()
Day 1 과정은 여기까지입니다. 다음 수업 전까지 위의 자습 안내를 따라 진행하세요.