Reference · 인쇄용

Keras 회귀 기초 치트시트

keras/keras01.py ~ keras13_ddarung.py 전체에서 뽑은 핵심 사실. 객관식 시험 직전 5분에 읽을 문서.

0. 모든 파일이 공유하는 4단계 골격

#1. 데이터   → x, y 준비 · (필요하면) train/test 분리 · 스케일링
#2. 모델구성 → Sequential() + model.add(Dense(...))
#3. 컴파일·훈련 → model.compile(loss, optimizer) · model.fit(x, y, epochs, batch_size)
#4. 평가·예측 → model.evaluate(x_test, y_test) · model.predict(x_new)

이 4단계 주석은 keras01.py부터 keras13_ddarung.py까지 한 번도 바뀌지 않는다. 문제에서 "다음 코드의 빈칸"이 나오면 거의 이 순서 안의 한 칸이다.

1. 모델 구성: Sequential + Dense

표현
Sequential()레이어를 일렬로 쌓는 모델. add() 순서 = 데이터가 흐르는 순서
Dense(5)출력 노드(=유닛) 5개인 완전연결 레이어. units출력 크기
input_dim=3입력 특성(열) 3개. 첫 레이어에만 지정
input_shape=(3,)input_dim=3과 같은 뜻. 튜플이라 콤마 필수
마지막 Dense노드 수 = 샘플 하나당 예측할 값의 개수 = y의 열 개수. y가 1차원 (5,)이면 열이 없으니 Dense(1) (회귀에서 활성화 함수 없음 = linear)

Dense가 실제로 계산하는 식: output = activation(dot(input, kernel) + bias). activation을 안 주면 선형(a(x)=x) — 이 폴더의 모든 모델이 그렇다.[1]

파라미터 수 = (입력 수 × 노드 수) + 노드 수(bias). 예: Dense(5, input_dim=1) → 1×5+5 = 10개.

2. 데이터 shape 읽기 (keras07, keras08)

코드shape읽는 법
np.array(5)()0차원(스칼라). 숫자 하나, 축이 없음
np.array([1,2,3])(3,)1차원(벡터). 원소 3개
np.array([[1,2,3]])(1,3)2차원(행렬). 1행 3열
np.array([[1,2],[3,4],[5,6]])(3,2)2차원(행렬). 3행 2열
np.array([[[1,2],[3,4]],[[5,6],[7,8]]])(2,2,2)3차원 텐서. 대괄호 깊이 = 차원 수
규칙: 가장 바깥 대괄호의 원소 개수부터 세어 나간다. shape의 첫 숫자는 항상 샘플(행) 수, 마지막 숫자가 특성 수다. Dense의 input_dim마지막 숫자와 같아야 한다.
용어: "샘플"(sample) = 데이터 한 줄 — 표의 한 행, 예측 단위 하나를 말한다. 집값 데이터라면 "집 한 채", 자전거 대여 데이터라면 "하루치 기록" 하나가 1 샘플이다. 사이킷런 용어집: "a noun to indicate a single feature vector … n_samplesbeing the number of rows in a data array X"[6]. 같은 것을 instance(인스턴스) · data point(데이터 포인트) · observation(관측치) · 행(row)이라고도 부른다. 통계학의 "표본"과 혼동하지 말 것: 통계에서 표본은 관측값 집합 전체(데이터 100줄 = 표본 1개, 크기 100)를 뜻하지만, 머신러닝에서는 한 줄이 1 샘플이다(데이터 100줄 = 샘플 100개). 케라스·사이킷런 문서와 에러 메시지가 이 뜻으로 쓴다.

차원 수는 arr.ndim, shape는 arr.shape로 확인한다. 이름은 0차원 스칼라 / 1차원 벡터 / 2차원 행렬 / 3차원 이상 텐서지만, 엄밀히는 전부 텐서다(TensorFlow의 rank-N tensor). 이 폴더는 Dense만 쓰므로 2차원까지만 등장한다. 3차원은 RNN (샘플, 타임스텝, 특성), 4차원은 컬러 이미지 (샘플, 높이, 너비, 채널)에서 나온다.

전치(transpose)가 필요한 이유

x = np.array([[1,2,3,4,5], [6,7,8,9,10]])   # (2, 5) ← 샘플 2개, 특성 5개로 잘못 해석됨
x = x.T                                      # (5, 2) ← 샘플 5개, 특성 2개  ✔
y = np.array([1,2,3,4,5])                    # (5,)  ← 타깃(정답), 샘플 5개
# x.T == x.transpose()

y가 [1,2,3,4,5](샘플 5개)이므로 x의 행도 5여야 한다. x.T를 빼먹으면 shape 에러.

다:1 / 다:다 (MLP)

파일x.shapey.shape첫 레이어마지막 레이어
mlp1(5, 2)(5,)input_shape=(2,)Dense(1)
mlp2(10, 3)(10,)input_shape=(3,)Dense(1)
mlp3(10, 3)(10, 2)input_shape=(3,)Dense(2)
mlp4(10,)(10, 3)input_shape=(1,)Dense(3)
predict에 넣는 값도 2차원이어야 한다. 특성 3개 모델(input_shape=(3,))에 샘플 하나를 넣는다면:
model.predict(np.array([[10, 31, 211]]))   # (1, 3) ← 특성 3개인 샘플 1개  ✔
model.predict(np.array([10, 31, 211]))     # (3,)  ← 특성 1개인 샘플 3개로 읽힘  ✗
# ValueError: Expected shape (None, 3), but input has incompatible shape (3,)
shape의 첫 숫자가 항상 샘플 수이기 때문이다. 1차원 (3,)을 넣으면 Keras는 마지막에 축을 붙여 (3, 1)로 읽으므로 "샘플 3개, 특성 1개"가 되어 특성 수가 3과 맞지 않는다. keras01~keras03predict(np.array([1,2,3,4,5]))가 통과하는 건 그 모델이 input_dim=1이라 (5,)(5, 1) = "샘플 5개, 특성 1개"가 우연히 맞아떨어지기 때문이다. 특성이 2개 이상이면 곧바로 에러다.

3. 컴파일 & 훈련

인자이 폴더에서의 값의미
loss='mse'전 파일 동일Mean Squared Error = 평균제곱오차. 회귀의 기본 손실
optimizer='adam'전 파일 동일Adaptive Moment Estimation. 가중치 갱신 알고리즘 (기본으로 가장 무난)
epochs100~5000전체 데이터를 몇 바퀴 학습할지
batch_size1, 2, 4 / 생략가중치를 한 번 갱신할 때 쓰는 샘플 수. 생략하면 32[2]
validation_split=0.2keras11~13train의 20%를 검증용으로 떼어 학습에 쓰지 않는다
batch_size ↓ = 1 에폭당 갱신 횟수 ↑ → 보통 더 정밀하지만 느리다. 샘플 1062개 + batch_size=4 → 1 에폭 = ceil(1062/4) = 266 스텝.
validation_split은 섞지 않는다. 공식 문서: 셔플 전에 x·y의 마지막 부분에서 그 비율만큼을 잘라 쓴다.[2] 그래서 정렬된 데이터에 쓰면 검증셋이 편향된다.

하이퍼파라미터(keras06 주석): 노드 개수, 에폭 수, 레이어 깊이, 배치 사이즈. = 사람이 정하는 값. 가중치·bias는 학습으로 정해지므로 하이퍼파라미터가 아니다.

mse 계산 순서 = 이름을 거꾸로 읽기

Error(오차) → Squared(제곱) → Mean(평균) 순으로 계산한다.

mse = mean(square(y_true - y_pred))     # Keras 공식 문서의 정의식

# 정답 y = [1, 2, 3], 예측 ŷ = [1.5, 2, 2.0] 일 때
# 1) 오차: -0.5,  0,  +1.0
# 2) 제곱:  0.25, 0,   1.0
# 3) 평균: (0.25 + 0 + 1.0) / 3 = 0.4167   ← mse
왜 제곱하는가 — 두 가지 역할을 한다. (1) 부호 상쇄 방지: 제곱을 안 하면 -0.5+1.0이 서로 깎아먹어 오차가 작아 보인다. (2) 큰 오차에 큰 벌점: 오차가 2배면 벌점은 4배. 크게 틀린 샘플을 먼저 고치게 밀어붙이지만, 반대로 이상치(outlier) 하나가 손실 전체를 지배할 수 있다.
지표약자 풀이성격
mseMean Squared Errormean((y-ŷ)²)큰 오차에 민감. 회귀 기본 손실
maeMean Absolute Errormean(|y-ŷ|)이상치에 둔감. 단위가 원본과 같아 해석 쉬움
RMSERoot Mean Squared Errorsqrt(mse)mse의 제곱된 단위를 되돌림

mse의 약점은 단위가 제곱된다는 것. 집값을 만원 단위로 예측하면 mse의 단위는 "만원²"이라 값이 직관적으로 안 읽힌다. 그래서 학습은 loss='mse', 사람이 볼 지표는 RMSE·MAE로 따로 두는 조합이 흔하다. RMSE는 문자열 이름이 없어 클래스로 넣는다: model.compile(loss='mse', optimizer='adam', metrics=[keras.metrics.RootMeanSquaredError()]).

4. train / test 분리 (keras09~10)

# ① 수동             ② 슬라이싱                   ③ 사이킷런 (실전)
x_train = np.array(   x_train = x[:7]              x_train, x_test, y_train, y_test = \
    range(1,8))       x_test  = x[7:]                  train_test_split(x, y, train_size=0.8,
                                                            shuffle=True, random_state=42)
인자기본값효과
train_size=0.8train 80% / test 20%
shuffleTrue나누기 전에 섞는다[3]
random_state=42None섞는 순서 고정 → 재현 가능. 없으면 실행마다 결과가 달라진다[3]
반환 순서x_train, x_test, y_train, y_test — 순서를 바꿔 받으면 조용히 망가진다

왜 나누는가: 훈련에 쓴 데이터로 평가하면 점수가 부풀려진다. evaluate는 반드시 본 적 없는 x_test로.

5. 스케일링 (keras11~13)

scaler = StandardScaler()
x_train = scaler.fit_transform(x_train)   # train에서 평균·표준편차를 배우고 변환
x_test  = scaler.transform(x_test)        # test는 변환만 (fit 금지!)

각 열을 (x - 평균) / 표준편차로 바꿔 평균 0, 표준편차 1로 만든다.[4] 시험 포인트 x_testfit_transform을 쓰면 테스트 정보가 새어 들어간다(데이터 누수). y는 스케일링하지 않는다.

6. 평가 지표 (keras12)

지표코드좋은 값성질
MSEmean_squared_error(y_test, y_pred)작을수록오차를 제곱 → 큰 오차에 민감. 단위가 y의 제곱
RMSEnp.sqrt(mean_squared_error(...))작을수록MSE의 제곱근 → y와 같은 단위
MAEmean_absolute_error(y_test, y_pred)작을수록절댓값 평균 → 이상치에 덜 민감
r2_score(y_test, y_pred)1에 가까울수록최대 1, 음수도 가능. 평균만 예측하는 모델 = 0[5]
R²(결정계수)는 오차 크기가 아니라 "점수"다. 입력을 보지 않고 정답의 평균만 대답하는 모델을 기준선으로 두고, 그보다 오차를 몇 % 줄였는지를 잰다. 그래서 방향이 MSE와 반대(1에 가까울수록 좋음)다.
R² = 1 - SSE / SST
#   SSE = Σ(y_test - y_pred)²      내 모델의 오차합
#   SST = Σ(y_test - y_test.mean())²  평균만 예측하는 모델의 오차합

# y_test = [100, 200, 300, 400, 500] (평균 300, SST = 100000) 일 때
# 예측 [110,190,310,390,505] → SSE=    425 → R² =  0.9958   오차 99.6% 줄임
# 예측 [300,300,300,300,300] → SSE= 100000 → R² =  0.0000   기준선과 동급
# 예측 [500,400,300,200,100] → SSE= 400000 → R² = -3.0000   기준선보다 나쁨
MSE와 함께 쓰는 이유: MSE는 단위에 딸려 변해서 값만 보고는 좋은지 알 수 없다. 위 "좋은 모델"을 만원 단위로 재면 mse=85, 원 단위로 재면 mse=85억이지만 R²는 둘 다 0.9958이다. R²는 무단위라 다른 데이터셋끼리도 비교할 수 있다. 그래서 학습·튜닝은 MSE, 성능 판정은 R²로 나눠 쓴다.

RMSE는 사이킷런에 없어서 직접 만든다 — keras12의 세 파일 모두 같은 함수:

def RMSE(y_test, y_pred):
    return np.sqrt(mean_squared_error(y_test, y_pred))

사이킷런 지표의 인자 순서는 항상 (y_true, y_pred) = (y_test, y_pred), 즉 실제값이 먼저다. MSE·MAE는 차이를 제곱·절댓값 처리하므로 뒤집어도 값이 같지만, R²는 첫 인자의 분산을 기준으로 삼아 뒤집으면 다른 값이 나온다 — 에러 없이 조용히 틀린다.

evaluate의 loss = 직접 계산한 MSE. loss='mse'로 컴파일했다면 아래 두 경로는 같은 값을 준다 — MSE를 따로 구할 필요가 없다.
loss = model.evaluate(x_test, y_test)              # ① Keras가 계산

y_pred = model.predict(x_test)
mse    = mean_squared_error(y_test, y_pred)        # ② 사이킷런으로 계산 (위 표)
# loss == mse  (같은 데이터 x_test/y_test + 같은 수식)
조건 두 가지: (1) loss='mae' 등으로 컴파일하면 당연히 MSE가 아니다. (2) metrics=[...]를 주면 반환값이 스칼라가 아니라 [loss, metric1, ...] 리스트다.

fit 로그의 losstrain MSE, val_lossvalidation MSE로 위 값과 전부 다르다. 본 적 없는 데이터로 잰 evaluate 값만이 신뢰할 수 있는 성능이다.

7. 데이터셋별 input_dim

파일불러오기x.shapeinput_dim
bostonboston_housing.load_data()(x_train,y_train),(x_test,y_test)(404, 13) / (102, 13)13
californiafetch_california_housing().data / .target(20640, 8)8
diabetesload_diabetes().data / .target(442, 10)10
따릉이pd.read_csv(..., index_col=0)(1328, 9) ※ count 제외9
boston_housing이미 train/test로 나뉘어 오므로 train_test_split이 필요 없다. 사이킷런 load_*/fetch_*x = datasets.data, y = datasets.target으로 꺼내 직접 나눈다.

8. CSV 데이터 (keras13 따릉이)

train_csv = pd.read_csv(path + "train.csv", index_col=0)  # 0번째 열을 인덱스로 → 특성에서 제외
train_csv = train_csv.dropna()                            # 결측치 행 삭제 (1459 → 1328)
x = train_csv.drop(["count"], axis=1)                     # axis=1 = 열 삭제 → (1328, 9)
y = train_csv["count"]                                    # 타깃 열
표현의미
index_col=0첫 열(id/날짜)을 인덱스로. 안 쓰면 특성이 10개가 되어 input_dim이 틀어진다
dropna()NaN이 있는 제거. train은 10열, test는 9열(count 없음)
drop([...], axis=1)axis=0=행, axis=1=열
train_csv.shape (1328, 10)x 9열 + y(count) 1열

9. 자주 나오는 함정

함정정답
model.evaluate(x_train, y_train)model.evaluate(x_test, y_test)로. 훈련에 쓴 데이터 점수는 부풀려져 신뢰할 수 없다
scaler.fit_transform(x_test)scaler.transform(x_test)만. fitx_train에서 한 번뿐(여기서의 fit은 모델이 아니라 스케일러fit). x_test로 fit하면 데이터 누출
y가 (10,2)인데 마지막을 Dense(1)Dense(2). keras01~mlp2가 전부 Dense(1)이라 손이 기억해 버린다. 마지막 노드 수 = 샘플 하나당 예측할 값의 개수(= y의 열 수). 중간 레이어 숫자는 y와 무관 — mlp3_1Dense(3) 다음이 Dense(2)
특성 3개 모델에 predict(np.array([10, 31, 211]))[[10, 31, 211]]로 2차원. 1차원 (3,)은 "특성 3개인 샘플 1개"가 아니라 (3,1)="샘플 3개, 특성 1개"로 읽혀 ValueError. keras01~03input_dim=1이라 1차원이 통과했을 뿐
r2_score(y_pred, y_test)r2_score(y_test, y_pred). 사이킷런은 (y_true, y_pred) = (실제값, 예측값) 순서이고 y_truey_test다. MSE·MAE는 뒤집어도 값이 같지만 R²는 조용히 다른 값이 나온다(에러 없음)

인용

  1. Keras 3 API — Dense layer: output = activation(dot(input, kernel) + bias), 기본 activation은 linear.
  2. Keras 3 API — Model training APIs (fit): "If unspecified, batch_size will default to 32"; validation 데이터는 "selected from the last samples … before shuffling".
  3. scikit-learn — train_test_split: shuffle 기본 True, random_state는 재현성 제어, test_size/train_size 모두 None이면 test 0.25.
  4. scikit-learn — StandardScaler: z = (x - u) / s.
  5. scikit-learn — r2_score: "Best possible score is 1.0 and it can be negative"; 평균만 예측하는 모델은 0.0.
  6. scikit-learn — Glossary, sample: "a noun to indicate a single feature vector. Elsewhere a sample is called an instance, data point, or observation. n_samples … being the number of rows in a data array X".