문제점 정의
데이터가 한번에 들어오는 것이 아니라 조금씩 조금씩 데이터가 추가된다.
1. 데이터가 들어올 때마다 훈련을 다시? -> 저장공간과 훈련 시키는데 점점 더 많은 시간이 소요
2. 이전에 가지고 있던 데이터를 조금 버려서 데이터 크기 유지? -> 버려진 데이터에 중요한 데이터가 있다면? ㅋ
결국 선택한 방법: 훈련시켜 둔 기존 모델을 버리지 말고 새로운 데이터만 추가로 학습 시키자!
-> 점진적 학습/온라인 학습이라고함. 확률적 경사 하강법이 이중 한개!!
확률적 경사 하강법
훈련 세트에서 샘플 하나씩 꺼내 손실 함수의 경사를 따라 최적의 모델을 찾는 알고리즘.

손실 함수
손실 함수는 어떤 문제에서 머신러닝 알고리즘이 얼마나 엉터리인지를 측정하는 기준이다. 그렇다면 역시 손실 함수 값이 작은 것이 좋을 것이다. 분류에서의 손실은 타겟값을 맞추지 못하는 것이다.
(-1) X 예측 확률 X 타겟(양성이냐 음성이냐)
위의 값이 손실 함수의 결과이다. 그런데, 음성 클래스(0)가 타겟이라면 무조건 0이된다. 이럴 경우에는 타겟을 마치 양성 클래스처럼 바꿔 1로 만들어준다. 그러면 예측확률 = 1 - 예측확률 로 업데이트 해주면 된다.
음수를 취해주는 이유는 손실이 작아야지 좋은 값인데, 양수인 상태에서는 확률이 높으면 손실 값이 높게 판단되므로 간단하게 음수로 만들어준다. 하지만 손실이 음수가 되면 매우 헷갈린다. 따라서 예측 확률에 로그를 씌운다!! 로그 함수는 0에 가까울수록 아주 큰 음수가 된다. 따라서 최종 손실 함수는 다음과 같이 된다.
타겟 = 1일때: (-1) X log(예측 확률)
타겟 = 0일때: (-1) X log(1 - 예측확률)
이 손실 함수를 로지스틱 손실 함수, 또는 이진 크로스엔트로피 손실 함수 라고 한다. 다중 분류에서 사용하는 손실함수는 크로스엔트로피 손실 함수 라고 한다.
자 그럼 이제 SGDClassifier 클래스를 활용해 보겠다.
SGDClassifier(Stochastic Gradient Descent)
우선 데이터 전처리 해주겠다.
import pandas as pd
fish = pd.read_csv('https://bit.ly/fish_csv_data')
fish_input = fish[['Weight', 'Length', 'Diagonal', 'Height', 'Width']]
fish_target= fish['Species']
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(fish_input, fish_target, random_state=42)
from sklearn.preprocessing import StandardScaler
ss=StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
SGDClassifier 은 loss , max_iter, tol 매개변수가 있다. loss는 어떤 손실 함수를 적용시킬 지 결정하는 매개 변수이고 max_iter은 몇번의 학습을 시킬건지 횟수를 정한다. tol 매개변수는 SGDClassifier 에서 일정 에포크 동안 성능이 향상되지 않으면 더 훈련하지 않고 자동으로 멈추는데, 이때 향상될 최솟값을 지정하는 매개변수이다. None으로 지정하면 멈추지 않고 내가 설정한 max_iter만큼 무조건 반복하게 해준다.
우선 10번만 학습시켜서 점수를 확인해본다.
from sklearn.linear_model import SGDClassifier
sc=SGDClassifier(loss='log_loss', max_iter=10, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
0.773109243697479
0.775
/usr/local/lib/python3.12/dist-packages/sklearn/linear_model/_stochastic_gradient.py:738: ConvergenceWarning: Maximum number of iteration reached before convergence. Consider increasing max_iter to improve the fit.
warnings.warn(
점수가 좀 낮다. SGDClassifier 에서는 partial_fit() 메서드를 활용해서 1 에포크씩 이어서 훈련할 수 있다.
sc.partial_fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
0.7983193277310925
0.775
점수가 조금 높아진 것을 확인할 수 있다. 최적의 에포크 수를 찾아보겠다.
import numpy as np
sc=SGDClassifier(loss='log_loss', random_state=42)
train_score=[]
test_score=[]
c= np.unique(train_target)
for _ in range(300):
sc.partial_fit(train_scaled, train_target, classes=c)
train_score.append(sc.score(train_scaled, train_target))
test_score.append(sc.score(test_scaled, test_target))
train_target에 unique해준 이유는 SGDClassifier 에서 partial_fit() 메서드만 사용하려면 훈련 세트에 있는 전체 클래스의 레이블을 매개변수로 넣어줘야한다. 총 300번 에포크를 돌리면서 sc를 훈련시킨다. 그 후, 각 에포크 별 점수를 그래프로 그려본다.
import matplotlib.pyplot as plt
plt.plot(train_score)
plt.plot(test_score)
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()

그려진 그래프를 보면 100번의 에포크 이후에 테스트 세트에 비해서 훈련 세트의 점수가 점점 높아지는 것을 볼 수 있따. 이에 따라 최적의 에포크는 100번이라는 것을 유추할 수 있다. 그럼 이제 tol=None으로 놓고 100번의 에포크로 모델을 훈련시켜 점수를 확인해보면?
sc=SGDClassifier(loss='log_loss', max_iter=100,tol=None, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
0.957983193277311
0.925
후....지렸다.
'ML' 카테고리의 다른 글
| ML/ 로지스틱 회귀, 이진 분류 vs 다중 분류 (0) | 2026.01.15 |
|---|---|
| ML/ 선형 회귀, 다항 회귀, 다중 회귀, 릿지, 라쏘 (0) | 2026.01.14 |
| ML/ k-최근접 이웃 회귀로 무게 예측하기 (0) | 2026.01.14 |
| ML/ 데이터 전처리 방법 (0) | 2026.01.13 |
| ML/ 훈련 세트와 테스트 세트 분리 (0) | 2026.01.13 |