검색
← 모듈 로드맵

실습 준비: 파이썬 · 넘파이 · scikit-learn · PyTorch 최소한

강의 · 입문자 · KAITABASE 정리

넘파이 배열 · 브로드캐스팅 · scikit-learn fit/predict · PyTorch 자동 미분을 실행하며 익히는 실습 준비

먼저 알아야 할 것

파이썬 기초 문법일차 함수평균 · 표준편차

다루는 내용

과정 내내 쓰는 세 도구의 최소한을 실제 실행 출력과 함께 익힙니다. 넘파이 배열의 모양 · 원소별 곱과 행렬 곱 · 축과 브로드캐스팅 · 벡터화(반복문 대비 속도 측정), scikit-learn 추정기의 fit · predict · transform 흐름과 데이터 누수 방지, PyTorch 텐서 · autograd · 네 단계 학습 루프를 다룹니다.

해설

실습 준비: 파이썬 · 넘파이 · scikit-learn · PyTorch 최소한

이 과정의 실습과 프로젝트는 넘파이(NumPy) · scikit-learn · PyTorch 세 도구로 합니다. 이 수업은 세 도구에서 꼭 필요한 것만 — 배열과 모양(shape), 브로드캐스팅, 벡터화, fit · predict · transform, 텐서와 자동 미분 — 을 실제로 실행한 코드와 출력으로 익힙니다.

항목내용
참고 자료NumPy 'absolute beginners' 안내 · numpy.org/doc/stable/user/absolute_beginners.html, scikit-learn 'Getting Started', PyTorch 튜토리얼
트랙 · 수준입문 · 입문
이 수업의 범위설치, 배열 만들기와 모양, 원소별 연산 · 행렬 곱, 축(axis), 브로드캐스팅, 벡터화, scikit-learn의 추정기 API(fit · predict · transform · score), 학습 · 테스트 나누기, PyTorch 텐서 · autograd · 최소 학습 루프
먼저 알면 좋은 것파이썬 기초 문법(변수 · 리스트 · for 문 · 함수)
실행 환경Python 3.14, numpy 2.5.1, scikit-learn 1.9.0, torch 2.14.0+cpu, CPU (이 글의 출력은 모두 이 환경에서 실제로 실행한 결과)

들어가기 전에

  • AI란 무엇인가 — 모델 · 파라미터 · 손실 · 학습 · 추론이라는 낱말을 알고 오면 코드가 무엇을 하는지 바로 보입니다.
  • 구글 머신러닝 단기 집중 과정 — 선형 회귀와 경사 하강법을 한 번 본 뒤라면 6절의 학습 루프가 쉽게 읽힙니다.

한눈에 보기

  • 넘파이 배열의 모양(shape)을 읽고, 원소별 곱 *과 행렬 곱 @을 구분합니다.
  • 브로드캐스팅 규칙으로 "열마다 평균 빼기" 같은 연산을 반복문 없이 씁니다.
  • 반복문 대신 벡터화하면 왜 수백~수천 배 빨라지는지 직접 잽니다.
  • scikit-learn의 모든 모델이 공유하는 fit → predict / transform 흐름을 익힙니다.
  • PyTorch의 자동 미분(autograd)으로 기울기를 구하고, 다섯 줄짜리 학습 루프를 이해합니다.

0. 설치

가장 단순한 방법은 파이썬을 설치한 뒤 터미널에서 다음을 실행하는 것입니다.

bash
python -m pip install numpy scikit-learn torch

GPU가 없어도 이 과정의 모든 실습은 CPU로 돌아갑니다. PyTorch의 GPU 판 설치 명령은 운영체제와 CUDA 버전에 따라 다르므로 PyTorch 공식 설치 페이지의 안내를 따르세요. 브라우저만으로 하고 싶다면 Google Colab 같은 노트북 환경에도 세 도구가 대개 미리 깔려 있습니다.

1. 넘파이 배열과 모양

직관(해설용 비유): 넘파이 배열은 "같은 종류의 숫자를 빈틈없이 줄 세운 표"입니다. 엑셀 표처럼 행과 열이 있고, 표의 크기를 모양(shape)이라고 합니다.

python
import numpy as np
x = np.array([1.0, 2.0, 3.0])
A = np.array([[1, 2, 3],
              [4, 5, 6]])
print(x.shape, A.shape, A.dtype)
print(A.T.shape)

실행 출력:

코드
(3,) (2, 3) int64
(3, 2)
표현뜻
(3,)원소 3개인 1차원 배열(벡터)
(2, 3)2행 3열 2차원 배열(행렬)
dtype원소 자료형 — 정수는 int64, 소수는 float64
A.T전치(transpose) — 행과 열을 바꿈, 모양 (3, 2)

왜 모양부터 보나: 실습 오류의 대부분은 "모양이 안 맞는다"입니다. 코드를 짤 때 배열마다 모양을 주석으로 적어 두는 습관이 가장 효과적인 디버깅입니다. 머신러닝에서는 보통 데이터 행렬 XX의 모양을 (예제 수, 특성 수)로 둡니다. scikit-learn 문서도 입력 XX를 (n_samples, n_features) 모양, 즉 행이 예제 · 열이 특성인 표로 받는다고 설명합니다.

2. 원소별 연산과 행렬 곱

python
print(x * 2)    # 원소마다 2배
print(x * x)    # 원소끼리 곱
print(A @ x)    # 행렬 곱 (2×3)·(3,) → (2,)

실행 출력:

코드
[2. 4. 6.]
[1. 4. 9.]
[14. 32.]

숫자로 해 보기(해설용): A @ x의 첫 원소는 AA의 첫 행 (1,2,3)(1, 2, 3)과 x=(1,2,3)x = (1, 2, 3)의 내적 1⋅1+2⋅2+3⋅3=141\cdot1 + 2\cdot2 + 3\cdot3 = 14, 둘째는 4+10+18=324 + 10 + 18 = 32입니다. 출력과 같습니다. 행렬 곱은 선형대수 1에서 자세히 봅니다.

연산자뜻모양 규칙
*원소별 곱(element-wise)모양이 같거나 브로드캐스팅 가능해야 함
@행렬 곱앞의 열 수 = 뒤의 행 수

3. 축(axis)과 브로드캐스팅

직관: axis=0은 "행 방향으로 접기(열마다 계산)", axis=1은 "열 방향으로 접기(행마다 계산)"입니다. 브로드캐스팅(broadcasting)은 모양이 다른 배열끼리 연산할 때 작은 쪽을 자동으로 늘려 맞추는 규칙입니다.

규칙(넘파이 문서): 두 배열의 모양을 끝 차원부터 비교해, 각 차원이 같거나 한쪽이 1이면 호환됩니다. 그렇지 않으면 ValueError: operands could not be broadcast together가 납니다.

python
X = np.array([[1.0, 10.0],
              [2.0, 20.0],
              [3.0, 30.0]])      # 모양 (3, 2)
mu = X.mean(axis=0)              # 열 평균, 모양 (2,)
sd = X.std(axis=0)               # 열 표준편차, 모양 (2,)
Z = (X - mu) / sd                # (3,2) - (2,) → 브로드캐스팅
print(mu, sd)
print(np.round(Z, 3))

실행 출력:

코드
[ 2. 20.] [0.81649658 8.16496581]
[[-1.225 -1.225]
 [ 0.     0.   ]
 [ 1.225  1.225]]

숫자로 해 보기(해설용): 첫 열 1,2,31, 2, 3의 평균은 2, 편차 −1,0,1-1, 0, 1의 제곱 평균은 2/32/3, 표준편차는 2/3≈0.8165\sqrt{2/3} \approx 0.8165입니다. 따라서 표준화 값은 −1/0.8165≈−1.225-1/0.8165 \approx -1.225입니다. 넘파이 std는 기본으로 nn으로 나누는 표준편차(ddof=0)를 씁니다. n−1n-1로 나누려면 ddof=1을 줍니다.

모양 A모양 B결과
(3, 2)(2,)(3, 2) — B를 행마다 복사한 것처럼
(3, 1)(4,)(3, 4) — 양쪽 다 늘어남
(3, 2)(3,)오류 — 끝 차원 2와 3이 다르고 둘 다 1이 아님

세 번째 경우에 "행마다 다른 값을 빼고" 싶다면 B[:, None]으로 모양을 (3, 1)로 바꿔 줍니다.

4. 벡터화: 반복문을 배열 연산으로

직관: 파이썬 for 문은 원소 하나마다 해석기를 거칩니다. 넘파이 배열 연산은 같은 일을 미리 컴파일된 코드로 한꺼번에 합니다. 그래서 벡터화(vectorization)가 머신러닝 코드의 기본 습관입니다.

python
import time
rng = np.random.default_rng(0)
a = rng.standard_normal(1_000_000); b = rng.standard_normal(1_000_000)
t0 = time.perf_counter(); s = 0.0
for i in range(len(a)): s += a[i] * b[i]
t1 = time.perf_counter(); s2 = a @ b; t2 = time.perf_counter()
print(f"반복문 {t1-t0:.3f}s, 벡터화 {t2-t1:.5f}s, 같은 값? {np.isclose(s, s2)}")

실행 출력(이 환경에서 한 번 잰 값 — 컴퓨터마다 다름):

코드
반복문 1.834s, 벡터화 0.00075s, 같은 값? True

백만 개 원소의 내적에서 두 방식의 결과는 같고, 시간은 이 측정에서 2,000배 넘게 차이 났습니다. 신경망 한 층의 계산도 결국 "행렬 곱 + 원소별 함수"라서, 벡터화해 두면 GPU로 옮길 때도 그대로 빨라집니다.

5. scikit-learn: 모든 모델이 같은 사용법

직관: scikit-learn의 모델은 모두 추정기(estimator)라는 같은 틀을 따릅니다. 배우는 것은 fit, 쓰는 것은 predict 또는 transform입니다. 모델을 바꿔도 코드는 거의 그대로입니다.

메서드하는 일예
fit(X, y)데이터로 파라미터를 학습회귀 계수, 평균 · 표준편차
predict(X)새 입력의 예측범주, 숫자
predict_proba(X)범주별 확률 (분류기 일부)[[0.97, 0.03, 0.0]]
transform(X)학습한 규칙으로 데이터 변환표준화, PCA
score(X, y)기본 평가 지표분류기는 정확도
python
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

Xi, yi = load_iris(return_X_y=True)
print(Xi.shape, yi.shape)
Xtr, Xte, ytr, yte = train_test_split(Xi, yi, test_size=0.25,
                                      random_state=0, stratify=yi)
sc = StandardScaler().fit(Xtr)              # 학습 데이터로만 평균 · 표준편차 학습
clf = LogisticRegression(max_iter=1000).fit(sc.transform(Xtr), ytr)
print("테스트 정확도:", round(clf.score(sc.transform(Xte), yte), 3))
print("첫 3개 예측:", clf.predict(sc.transform(Xte[:3])), "정답:", yte[:3])
print("확률:", np.round(clf.predict_proba(sc.transform(Xte[:1])), 3))

실행 출력:

코드
(150, 4) (150,)
테스트 정확도: 0.974
첫 3개 예측: [0 0 0] 정답: [0 0 0]
확률: [[0.971 0.029 0.   ]]

붓꽃(iris) 데이터는 꽃 150송이의 특성 4개(꽃받침 · 꽃잎의 길이와 너비)와 품종 3개 라벨로 이뤄진, scikit-learn에 들어 있는 작은 데이터입니다. 테스트 38송이 중 37송이를 맞혀 정확도 0.974가 나왔습니다.

왜 fit을 학습 데이터에만 하나: 표준화의 평균 · 표준편차를 전체 데이터로 구하면 테스트 데이터의 정보가 학습에 섞입니다. 이것이 데이터 누수(data leakage)입니다. 규칙은 "변환기도 학습 데이터로만 fit하고, 테스트에는 transform만" 입니다. 이 실수를 구조적으로 막는 Pipeline은 특성 공학과 데이터 전처리에서 다룹니다. stratify=yi는 학습 · 테스트에 품종 비율을 똑같이 맞추라는 뜻이고, random_state는 결과를 다시 똑같이 얻기 위한 난수 시드입니다.

6. PyTorch: 텐서와 자동 미분

직관: PyTorch의 텐서(tensor)는 넘파이 배열과 거의 같지만 두 가지가 더 있습니다. ① GPU로 옮길 수 있고, ② 계산 과정을 기억해 기울기(미분값)를 자동으로 구합니다. 신경망 학습에 필요한 것은 바로 이 기울기입니다.

python
import torch
torch.manual_seed(0)
t = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
print(t.shape, t.dtype)
print(t @ t)

w = torch.tensor(2.0, requires_grad=True)
y = w**2 + 3*w
y.backward()
print("y =", y.item(), " dy/dw =", w.grad.item())

실행 출력:

코드
torch.Size([2, 2]) torch.float32
tensor([[ 7., 10.],
        [15., 22.]])
y = 10.0  dy/dw = 7.0

숫자로 해 보기(해설용): y=w2+3wy = w^2 + 3w를 미분하면 dy/dw=2w+3dy/dw = 2w + 3이고, w=2w = 2에서 2⋅2+3=72 \cdot 2 + 3 = 7입니다. PyTorch가 낸 7.0과 같습니다. requires_grad=True는 "이 값에 대한 기울기를 추적하라", backward()는 "끝에서부터 거꾸로 미분하라"는 뜻입니다. 거꾸로 미분하는 원리(역전파)는 역전파를 계산 그래프로 손계산하기에서 봅니다.

다섯 줄 학습 루프

데이터 y=2x+1y = 2x + 1을 선형 모델로 배우는 가장 작은 예입니다.

python
xs = torch.tensor([[0.0],[1.0],[2.0],[3.0]]); ys = 2*xs + 1
model = torch.nn.Linear(1, 1)                 # y = w x + b
opt = torch.optim.SGD(model.parameters(), lr=0.1)
for step in range(200):
    opt.zero_grad()                           # ① 지난 기울기 지우기
    loss = ((model(xs) - ys)**2).mean()       # ② 예측 → 손실(MSE)
    loss.backward()                           # ③ 기울기 계산
    opt.step()                                # ④ 파라미터 갱신
print("학습된 w, b:", round(model.weight.item(), 3), round(model.bias.item(), 3),
      " 손실:", f"{loss.item():.2e}")

실행 출력:

코드
학습된 w, b: 2.0 1.0  손실: 1.48e-12
mermaid
flowchart LR
  A[데이터 xs, ys] --> B[모델 예측 model xs]
  B --> C[손실 계산 MSE]
  C --> D[loss.backward 기울기]
  D --> E[opt.step 파라미터 갱신]
  E --> F[opt.zero_grad 기울기 초기화]
  F --> B
  E --> G[학습 끝: w≈2, b≈1]

왜 zero_grad가 필요한가: PyTorch는 기울기를 덮어쓰지 않고 더해 쌓습니다. 여러 묶음의 기울기를 모으고 싶을 때 편하게 하려는 설계입니다. 그래서 매 걸음 처음에 지우지 않으면 지난 기울기가 섞여 학습이 엉뚱하게 흘러갑니다. 이 네 단계(지우기 → 손실 → backward → step)는 앞으로 나올 모든 PyTorch 코드에서 똑같이 반복됩니다.

세 도구는 언제 쓰나

도구잘하는 일이 과정에서
넘파이배열 계산, 손계산 검산수학 트랙 검산, 넘파이로 신경망 만들기
scikit-learn표 형태 데이터의 고전 머신러닝, 전처리 · 평가머신러닝 트랙 전체, 손글씨 숫자 분류기
PyTorch신경망 정의 · 자동 미분 · GPU 학습딥러닝 트랙, PyTorch로 CNN 학습하기

연습 문제

1. 모양 (5, 3)인 X와 (3,)인 w가 있습니다. X @ w와 X * w의 모양은?

풀이: X @ w는 (5×3)·(3,) → (5,)입니다. X * w는 브로드캐스팅으로 w를 행마다 곱해 (5, 3)입니다.

2. 모양 (4, 3)인 X에서 행마다(예제마다) 평균을 빼려고 X - X.mean(axis=1)을 쓰면 왜 오류가 나고, 어떻게 고치나요?

풀이: X.mean(axis=1)의 모양은 (4,)라서 (4, 3)과 끝 차원 3 · 4가 맞지 않습니다. X - X.mean(axis=1, keepdims=True) 또는 X - X.mean(axis=1)[:, None]로 모양을 (4, 1)로 만들면 됩니다.

3. y = 3*w**2에서 w = 1일 때 y.backward() 뒤 w.grad는?

풀이: dy/dw=6w=6dy/dw = 6w = 6입니다.

4. 아래 코드의 문제점은?

python
sc = StandardScaler().fit(X)          # X는 전체 데이터
Xtr, Xte = train_test_split(sc.transform(X), test_size=0.2)

풀이: 전체 데이터로 평균 · 표준편차를 구해 테스트 정보가 새어 들어갑니다(데이터 누수). 먼저 나누고, 학습 데이터로만 fit한 뒤 두 묶음에 transform해야 합니다.

스스로 점검

  1. 넘파이에서 *와 @는 어떻게 다른가요?
    • 답: *는 같은 자리 원소끼리 곱하는 원소별 곱이고, @는 행과 열의 내적으로 이뤄진 행렬 곱입니다.
  2. scikit-learn에서 fit과 transform을 나누어 둔 이유는?
    • 답: 학습 데이터에서 배운 규칙(평균, 주성분 등)을 테스트 · 실서비스 데이터에 똑같이 적용하기 위해서입니다. 새 데이터로 다시 fit하면 규칙이 바뀌고 누수가 생깁니다.
  3. PyTorch 학습 루프에서 loss.backward()와 opt.step()은 각각 무엇을 하나요?
    • 답: backward()는 손실에 대한 각 파라미터의 기울기를 계산해 .grad에 쌓고, step()은 그 기울기로 파라미터를 실제로 갱신합니다.

용어 정리

용어쉬운 뜻
배열(array) · 텐서(tensor)같은 자료형 숫자를 여러 차원으로 늘어놓은 묶음
모양(shape)배열의 각 차원 크기
축(axis)계산을 따라 접을 차원
브로드캐스팅(broadcasting)모양이 다른 배열을 자동으로 늘려 맞추는 규칙
벡터화(vectorization)반복문 대신 배열 연산 한 번으로 쓰기
추정기(estimator)scikit-learn에서 fit으로 학습하는 모든 객체
데이터 누수(data leakage)평가 데이터 정보가 학습에 섞이는 실수
난수 시드(random seed)같은 난수를 다시 얻기 위한 시작값
자동 미분(autograd)계산 과정을 기록해 기울기를 자동으로 구하는 기능
옵티마이저(optimizer)기울기로 파라미터를 고치는 규칙(SGD, Adam 등)

더 깊이 보려면

NumPy의 'absolute beginners' 안내는 배열 만들기 · 인덱싱 · 모양 바꾸기 · 브로드캐스팅 · 기본 통계를 한 페이지에 모아 두었고, 'Broadcasting' 문서는 규칙을 그림과 함께 설명합니다. scikit-learn 'Getting Started'는 추정기 · 변환기 · 파이프라인 · 교차 검증을 짧게 소개합니다. PyTorch 공식 튜토리얼의 'Learn the Basics' 연재는 텐서 · 데이터 로딩 · 모델 만들기 · 자동 미분 · 최적화를 순서대로 다룹니다.

다음에 볼 것

라이선스

이 글은 원문 번역이 아니라 KAITABASE가 직접 쓴 해설이며, 코드는 직접 작성해 위 환경에서 실행했습니다. 숫자 예는 설명용입니다. NumPy · scikit-learn 문서는 BSD 계열 라이선스, PyTorch 튜토리얼은 BSD-3 라이선스로 공개되어 있습니다.

출처

AI 원리부터 이해하기 · 입문 모듈

입문 모듈 학습

이 글은 입문 모듈의 학습 자료입니다. 전체 6개 자료 중 4번째입니다.

AI 기초 과정은 현재 진도 저장을 지원하지 않습니다.

출처·원문

원문 보기

요약만

본문 자체 작성 · 참고 자료 NumPy 문서(BSD) · scikit-learn 문서(BSD) · PyTorch 문서