LLM 엔지니어링2장 · 신경망과 딥러닝의 기본 원리17 / 23← 이전목차다음 →MetaContents

2장. 신경망과 딥러닝의 기본 원리

실습 3 — 주문량 데이터 준비하기

가상 쇼핑몰의 2년 치 하루 주문량 daily_orders.csv 를 읽어 살펴보고, 신경망에 넣을 수 있도록 나누고 크기를 맞춘 뒤 텐서로 바꿉니다. 연습용으로 만든 가상 데이터입니다. 실습 4부터 6까지 이 준비를 그대로 다시 씁니다.

1단계. 읽고 살펴보기

Python
import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams["font.family"] = "Malgun Gothic"
plt.rcParams["axes.unicode_minus"] = False

df = pd.read_csv("daily_orders.csv")
print(df.shape)
print(df.head(3))
# 주문량의 요약: 평균, 최솟값, 최댓값 등
print(df["주문량"].describe().round(1))
출력
(731, 8)
           날짜  주말  공휴일   기온  강수mm  광고비만원  할인행사  주문량
0  2024-01-01   0    0 -1.8   0.0     86     0  233
1  2024-01-02   0    0 -1.4   0.0     89     1  303
2  2024-01-03   0    0  3.3   0.0     95     0  409
count    731.0
mean     506.1
std      102.5
min      181.0
25%      445.5
50%      521.0
75%      572.5
max      862.0
Name: 주문량, dtype: float64

이 단계의 함수입니다.

코드쉬운 뜻
plt.rcParams["font.family"] = "Malgun Gothic"그래프의 글꼴을 맑은 고딕으로 바꿔 한글이 깨지지 않게 한다
plt.rcParams["axes.unicode_minus"] = False눈금의 빼기 기호가 한글 글꼴에서 네모로 깨지지 않게 한다
pd.read_csv("daily_orders.csv")csv 파일을 읽어 표(DataFrame)로 만든다
df.shape, df.head(3)표의 (행 수, 열 수)와 맨 앞 3줄
df["주문량"].describe()한 열의 요약: 개수(count), 평균(mean), 표준편차(std), 최솟값, 사분위수(25%, 50%, 75%), 최댓값
.round(1)소수 첫째 자리까지 반올림해 보기 좋게 한다

2단계. 특성과 주문량의 관계 그려 보기

Python
# 기온과 광고비에 따라 주문량이 어떻게 달라지는지 점으로 찍어 본다
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
axes[0].scatter(df["기온"], df["주문량"], s=8, alpha=0.5)
axes[0].set_title("기온과 주문량")
axes[0].set_xlabel("기온")
axes[1].scatter(df["광고비만원"], df["주문량"], s=8, alpha=0.5)
axes[1].set_title("광고비와 주문량")
axes[1].set_xlabel("광고비(만원)")
plt.tight_layout()
plt.show()
기온과 주문량, 광고비와 주문량의 산점도

이 단계의 함수입니다.

코드쉬운 뜻
plt.subplots(1, 2, figsize=(11, 4))가로 11, 세로 4 크기의 그림에 그래프 칸 두 개를 나란히 만든다. axes[0] 이 왼쪽, axes[1] 이 오른쪽 칸이다
axes[0].scatter(x, y, s=8, alpha=0.5)점을 찍는 산점도를 그린다. s 는 점 크기, alpha 는 투명도(0.5 는 반투명)라 겹친 점이 진하게 보인다
set_title, set_xlabel칸의 제목과 가로축 이름을 단다
plt.tight_layout()두 칸의 글자가 겹치지 않게 간격을 맞춘다
plt.show()그림을 화면에 띄운다

3단계. 특성 고르고 나누기

Python
from sklearn.model_selection import train_test_split

# 날짜는 그대로 못 쓰므로 첫날부터 며칠째인지(일차)로 바꾼다
df["일차"] = range(len(df))
features = ["일차", "주말", "공휴일", "기온", "강수mm", "광고비만원", "할인행사"]
X = df[features]
y = df["주문량"]

# 학습용 80%, 시험용 20%. 회귀라서 stratify 는 쓰지 않는다
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print("학습용:", X_train.shape, "시험용:", X_test.shape)
출력
학습용: (584, 7) 시험용: (147, 7)

이 단계의 함수입니다.

코드쉬운 뜻
df["일차"] = range(len(df))0, 1, 2, … 를 새 열로 붙인다. 날짜를 "첫날부터 며칠째"라는 숫자로 바꾼 것이다
df[features]고른 열 일곱 개만 뽑은 표. 이것이 특성 X 다
train_test_split(X, y, test_size=0.2, random_state=42)행을 섞어 학습용 80%, 시험용 20% 로 나눈다. random_state 는 섞는 순서의 씨앗이다

4단계. 크기 맞추고 텐서로 바꾸기

Python
import torch
from sklearn.preprocessing import StandardScaler

# StandardScaler: 열마다 평균 0, 표준편차 1 로 맞춘다
# 광고비(20~200)와 공휴일(0, 1)처럼 크기가 다른 열을 같은 눈금으로 만들어 학습을 쉽게 한다
# fit 은 학습용에만 한다(시험용을 미리 보지 않도록)
scaler = StandardScaler().fit(X_train)
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)
print("맞춘 뒤 학습용 평균:", X_train_s.mean(axis=0).round(2))

# 텐서로 바꾼다. 주문량은 100 으로 나눠 '백 건' 단위로 줄인다(예: 520건 → 5.2)
# view(-1, 1) 은 (건수,) 모양을 (건수, 1) 로 바꿔 모델의 출력 모양과 맞춘다
X_train_t = torch.tensor(X_train_s, dtype=torch.float32)
y_train_t = torch.tensor(y_train.to_numpy() / 100, dtype=torch.float32).view(-1, 1)
X_test_t = torch.tensor(X_test_s, dtype=torch.float32)
print(X_train_t.shape, y_train_t.shape, X_test_t.shape)
출력
맞춘 뒤 학습용 평균: [ 0. -0. -0.  0. -0.  0. -0.]
torch.Size([584, 7]) torch.Size([584, 1]) torch.Size([147, 7])

이 단계의 함수입니다.

코드쉬운 뜻
StandardScaler().fit(X_train)학습용에서 열마다 평균과 표준편차를 재어 기억해 둔다
scaler.transform(X)기억한 평균을 빼고 표준편차로 나눈다. 학습용과 시험용에 같은 잣대를 쓴다
.mean(axis=0)열마다(세로로) 평균을 낸다
y_train.to_numpy() / 100주문량을 NumPy 배열로 꺼내 100 으로 나눈다
torch.tensor(..., dtype=torch.float32)배열을 float32 텐서로 바꾼다
.view(-1, 1)모양을 (건수, 1) 로 바꾼다. -1 은 "남은 칸 수에 맞춰 알아서"라는 뜻이다

이 실습이 뜻하는 것

이 실습은 요리를 하기 전에 재료를 손질하는 일과 같습니다. 장바구니에 무엇이 얼마나 들었는지 살펴보고(1단계), 재료끼리 어떻게 어울리는지 눈으로 확인하고(2단계), 쓸 재료를 골라 연습용과 시식용으로 나누고(3단계), 크기를 고르게 썰어 냄비에 담습니다(4단계). 여기서 장바구니가 daily_orders.csv, 연습용과 시식용이 학습용과 시험용, 고르게 썰기가 StandardScaler, 냄비가 텐서입니다. 연습용으로 만든 가상 데이터입니다.

단계출력뜻
1. 표의 모양(731, 8)2년 치 731일, 항목 8개짜리 표입니다
1. 주문량 요약mean 506.1, min 181.0, max 862.0하루 평균 506건쯤 주문이 들어오고, 적은 날은 181건, 많은 날은 862건입니다
2. 산점도기온·광고비와 주문량 그림기온은 가운데에서 주문이 많은 둥근 모양이고, 광고비는 늘수록 주문이 늘지만 점점 덜 늡니다. 둘 다 직선이 아닙니다
3. 나누기(584, 7), (147, 7)731일을 학습용 584일, 시험용 147일로 나눴습니다. 특성은 7개입니다
4. 크기 맞춤[ 0. -0. -0. 0. -0. 0. -0.]학습용의 열마다 평균이 0 이 되었습니다. -0. 은 아주 작은 음수를 반올림한 것으로 0 과 같습니다
4. 텐서[584, 7], [584, 1], [147, 7]특성과 정답이 신경망에 넣을 모양의 텐서가 되었습니다. 정답은 '백 건' 단위로 줄였습니다

한 줄로 줄이면, 주문량 표를 신경망이 먹을 수 있는 숫자 덩어리로 손질한 실습입니다. 실습 4부터 실습 6이 이 준비를 그대로 다시 적고 시작합니다. 아직 아무것도 학습하지 않았고, 그래프에서 본 곡선 모양은 "신경망이 쓸모 있을 것 같다"는 단서일 뿐 증명은 실습 6에서 기준선, 직선 모델과 견주어 합니다.

코드 설명

  • 2년 치 731일, 열 8개입니다. 하루 주문량은 평균 506.1건이고, 가장 적은 날 181건, 가장 많은 날 862건입니다.
  • 왼쪽 그래프에서 주문량은 기온이 너무 낮거나 높으면 줄고 가운데에서 많은 둥근 모양입니다. 오른쪽 그래프에서는 광고비가 늘수록 주문이 늘지만 점점 덜 늡니다. 둘 다 직선이 아닙니다. 이런 곡선 관계에서 신경망이 힘을 씁니다. 점의 색은 matplotlib 의 기본 색입니다.
  • StandardScaler 는 열마다 평균을 빼고 표준편차로 나눕니다. 맞춘 뒤 학습용의 평균이 모두 0 이 된 것을 출력에서 확인할 수 있습니다. -0. 은 아주 작은 음수가 반올림되어 찍힌 것으로, 0 과 같습니다. 시험용은 학습용의 평균과 표준편차로 바꾸므로 정확히 0 은 아닙니다.
  • 주문량을 100 으로 나눈 까닭은, 정답이 500 처럼 크면 처음에 0 근처를 내는 신경망이 거기까지 가는 데 오래 걸리기 때문입니다. 예측한 뒤에는 100 을 곱해 되돌립니다.
  • 시험용 정답(y_test)은 텐서로 바꾸지 않았습니다. 채점은 원래 단위(건)로 scikit-learn 의 MAE 함수로 하기 때문입니다.
← 이전 절2장 · 실습 2 — 자동 미분으로 직선 맞추기다음 절 →2장 · 실습 4 — 주문량 예측 신경망 학습하기