Post

chapter.4 다양한 분류 알고리즘

chapter.4 다양한 분류 알고리즘

4-1 로지스틱 회귀

판다스의 unique()함수를 사용하여 주어진 데이터에 어떤 종류의 생선이 있는지 확인

1
2
3
4
import pandas as pd
fish = pd.read_csv()
fish.head()
print(pd.unique(fish['Species'])) # output: ['Bream', 'Roach', 'Whitefish', 'Parkki', 'Perch', 'pike', 'Smelt' ]

이 데이터프레임에서 Species 열을 타깃으로 만들고 나머지 5개 열은 입력 데이터로 사용

1
fish_input = fish[['Weight', 'Length', 'Diagonal', 'Height', 'Width' ]].to_numpy()

타깃 데이터에 2개 이상의 클래스가 포함된 문제를 다중분류라고 한다.

1
2
3
# 테스트 세트에 있는 처음 5개 샘플의 타깃값 예측
print(kn.predict(test_scaled[:5]))
# output: ['Perch' 'Smelt' 'Pike' 'perch' 'Perch']

image1.png

※ 로지스틱 회귀
image1.png
z가 확률이 되려면 0~1 사이의 값을 가져야 하기 때문에 시그모이드 함수 또는 로지스틱 함수를 활용
image1.png

1
2
3
4
5
6
7
# 시그모이드 함수 출력
import numpy as np
import matplotlib.pyplot as plt
z = np.arange(-5,5,0.1)
phi = 1/(1+np.exp(-z))
plt.plot(z,phi)
plt.show()
1
2
3
4
bream_smelt_indexes = (train_target == 'Bream') | (train_target == 'Smelt')

train_bream_smelt = train_scaled[bream_smelt_indexes]
target_bream_smelt = train_target[bream_smelt_indexes]

훈련 세트에서 Bream과 Smelt 행만 골라내서 True 반환

1
2
3
4
5
6
7
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()

lr.fit(train_bream_smelt, target_bream_smelt)
print(lr.predict(train_bream_smelt[:5]))
# output: ['Bream' 'Smelt' 'Bream' 'Bream' 'Breaml]

_proba()를 통해 각 샘플의 예측 확률을 확인할 수 있음

1
2
3
4
5
6
7
8
print(lr.predict_proba(train_bream_smelt[:5]))
# output: [
#    [0.99759855, 0.00240145],
#    [0.02735183, 0.97264817],
#    [0.99486072, 0.00513928],
#    [0.98584202, 0.01415798],
#    [0.99767269, 0.00232731]
#]

이때 주의할 점은 사이킷런은 타깃값을 알파벳 순으로 정렬하기 때문에 Bream과 Smelt중 첫번째 열이 Bream으로 된다는 것을 알아야함.

1
2
3
4
5
6
7
8
9
# 로지스틱 회귀가 학습한 계수값 출력
print(lr.coef_, lr.intercept_)
# output: [[-0.4037798, -0.57620209, -0.66280298, -1.01290277, -0.73168947],[-2.16155132]

# 처음 5개 샘플의 z값 출력
decisions = lr.decision_function(train_bream_smelt[:5])
print(decisions)
# output: [-6.02927744  3.57123907 -5.26568906 -4.24321775 -6.0607117]

1
2
3
from scipy.special import expit
print(expit(decisions))
# output: [0.00240145, 0.97264817, 0.00513928, 0.01415798, 0.00232731]

→ scipy 라이브러리에서 expit()을 활용하여 시그모이드 함수에 값 대입

  • LogisticRegression 클래스는 기본적으로 반복적인 알고리즘을 사용한다. max_iter 매개변수에서 반복횟수를 지정하며 기본값은 100.
  • LogisticRegression은 기본적으로 릿지 회귀와 같이 L2 규제 사용
1
2
3
4
5
6
7
8
9
# alpha=20, 반복횟수 1000회로 설정
lr = LogisticRegression(C=20, max_iter=1000)

lr.fit(train_scaled, train_target)

print(lr.score(train_scaled, train_target))
print(lr.score(test_scaled, test_target))
# output: 0.93277
#         0.925

→ 결과를 통해 과대적합 or 과소적합이 되진 않았음

  • 다중 분류는 클래스마다 z값을 하나씩 계산하여 가장 높은 z값을 출력하는 클래스가 예측 클래스가 되는 구조
  • 다중 분류는 시그모이드 함수가 아닌 소프트맥스 함수를 사용하여 z값을 확률로 변환
1
2
3
4
5
decision = lr.decision_function(test_scaled[:5])

from scipy.special import softmax
proba = softmax(decision, axis=1)
print(np.round(proba, decimals=3))

softmax()함수에 decision 배열을 전달하여 확률값 출력
→ 앞서 구한 proba 배열과 일치하는 것을 볼 수 있다.

4-2 확률적 경사하강법

확률적 경사하강법이란?
확률적이란 ‘무작위’ 혹은 ‘랜덤하게’의 기술적인 표현, ‘경사’는 기울기를 의미한다. 즉 랜덤하게 하나의 샘플을 골라 가장 가파른 길을 선택하여 조금씩 내려가는 방식.
훈련세트에서 랜덤하게 샘플을 계속 선택하여 전체 샘플을 모두 사용할 때까지 진행
→ 데이터가 한번에 준비되지 못한 경우에 이전에 훈련한 모델을 버리지 않고 새로운 데이터에 대해서만 조금씩 더 훈련할 수 있다는 장점이 있음.

  • 만약 모든 샘플을 다 사용했음에도 다 내려오지 못한 상황이라면 훈련세트에 모든 샘플을 다시 채워넣어서 다시 랜덤하게 하나의 샘플을 선택하여 이어서 경사를 내려간다. 이렇게 확률적 경사 하강법에서 훈련세트를 한번 모두 사용하는 과정을 에포크 라고 한다. 일반적으로 경사하강법은 수십, 수백 번 이상 에포크를 수행한다,

  • 샘플 한개씩이 아닌 여러개의 샘플을 사용해 경사하강법을 수행하는 방식을 미니배치 경사 하강법 이라고 부른다.
  • 극단적으로 한 번 경사로를 따라 이동하기 위해 전체 샘플을 사용하는 방식을 배치 경사하강법 이라고 한다.
    image1.png

※ 손실함수(loss function)
어떤 문제에서 머신러닝 알고리즘이 얼마나 잘못되었는지를 측정하는 기준

  • 비용함수(cost function)과는 다른 개념이다. 손실함수는 샘플 하나에 대한 손실을 정의하고 비용함수는 훈련세트에 있는 모든 샘플에 대한 손실함수의 합을 말한다.

image1.png
예측 확률을 사용해 연속적인 손실 함수를 얻기 위해서 로그함수 활용(이진분류)
→ 이를 로지스틱 손실 함수 라고 부르며 다중 분류의 경우 사용하는 손실 함수를 크로스엔트로피 손실 함수 라고 부른다.

1
2
3
4
5
6
7
8
9
10
from sklearn.linear_model import SGDClassifier

# loss='log'로 지정하여 로지스틱 손실함수 지정. max_iter는 에포크 횟수 지정
sc = SGDClassifier(loss='log', 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))
# output: 0.773109243697479
#         0.775

→ 출력된 훈련 세트와 테스트 세트의 정확도가 낮은걸 보아 지정한 반복횟수 10번이 부족한것으로 판단
partial_fit()함수를 사용하면 fit()함수와 사용법이 같지만 호출할 때마다 1 에포크씩 이어서 훈련할 수 있다는 특징이 있음

1
2
3
sc.partial_fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))

※ 에포크와 과대/과소적합
에포크 횟수가 적으면 모델이 훈련 세트를 덜 학습하기 때문에 과소적합이 될 가능성이 높고 에포크 횟수가 크면 훈련세트에 너무 과대적합될 가능성이 높음.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# np_unique()함수로 train_target에 있는 7개 생선 목록 생성, 에포크마다 훈련세트와 테스트세트에 대한 점수 기록을 위해 2개의 리스트 준비  
import numpy as np
sc = SGDClassifier(loss='log', random_state=42)
train_score = []
test_score = []
classes = np.unique(train_target)

# 300번의 에포크 설정
for _ in range(0, 300):
    sc.partial_fit(train_scaled, train_target, classes=classes)
    train_score.append(sc.score(train_scaled, train_target))
    test_score.append(sc.score(test_scaled, test_target))

# 그래프 출력
import matplotlib.pyplot as plt

plt.plot(train_score)
plt.plot(test_score)
plt.show()

image1.png
위 그래프를 통해 에포크를 100으로 설정하는 것이 가장 적절하다는 것을 알 수 있음

1
2
3
4
5
6
7
sc = SGDClassifier(loss='log', 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))
# output: 0.957983193277311
#         0.925
  • 참고로 SGDClassifier의 loss매개변수의 기본값은 ‘hinge’이다. 힌지 손실은 서포트 벡터 머신 이라 불리는 또다른 머신러닝 알고리즘을 위한 손실 함수로 SGDClassifier는 여러 종류의 손실 함수를 loss 매개변수에 지정할 수 있다는 특징이 있다.
This post is licensed under CC BY 4.0 by the author.

Trending Tags