AI/혼자 공부하는 머신러닝+딥러닝 책

챕터 03 - 2

codehunter 2023. 7. 15. 10:49

머신러닝의 지도학습을 계속 익히고 있는중이다.

 

앞의 학습과정을 정리하면 (과정이 점점 늘고있다 ㅡㅡ;;;) 

 

1. 데이터 준비 및 데이터 패턴 파악하기 ( 주로 그래프들을 그려가며 대략적인 추세 파악 )

2. 만약 스케일이 안맞는 데이터들이라면 스케일 맞추기

3. 훈련세트와 테스트세트 준비하기

4. 특정 알고리즘 (여기선 k-최근접 이웃 알고리즘 ) 으로 훈련하기

5. 과소적합, 과대적합 파악해서 파라미터 조정하기

6. 평가

7. 예측 및 사용하기

 

앞의 과정을 거친 모델을 사용중에 예측 할 데이터로 다시 예측을 해보는데 실데이터와 예측데이터와 큰 차이가 발생했다면? 그럼 모델 사용에 또 뭔가 수정할 부분이 생겼다는 말이다. 그걸 살펴보자.

 

1. 데이터 준비 및 패턴 파악하기 ( 주로 그래프들을 그려가며 대략적인 추세 파악 )

2. 만약 스케일이 안맞는 데이터들이라면 스케일 맞추기

3. 훈련세트와 테스트세트 준비하기

4. 특정 알고리즘 (여기선 k-최근접 이웃 알고리즘 ) 으로 훈련하기

5. 과소적합, 과대적합 파악해서 파라미터 조정하기

여기까진 3-1과 동일하므로 패스

 

이제 이 모델로 길이가 50cm인 농어의 무게를 예측하면

무게예측값이 1033g 인데 실제 이 농어의 무게는 더 많이 나간다고 한다. 

그래서 그래프를 그려보고 주변 데이터를 찍어보면 확실히 좀 동떨어져서 예측할 농어값이 찍혀있는걸 알수 있는데

k-최근접 이웃 회귀 알고리즘이 50cm에 가까운 이웃들의 무게의 평균값을 구하기 때문에 이 샘플의 평균값을 찍어보면

위에서 예측한 값과 정확히 일치하는걸 알수 있다. 

즉 k-최근접 이웃 회귀 알고리즘은 훈련 세트의 데이터안에서 평균값을 구하기 때문에 50, 100, 150... 모두 1033 으로 예측하게 된다.

길이가 100cm인 농어의 그래프를 그려서 보면서 확인은 해보자.

이런식이면 농어가 아무리 커도 무게가 더 늘어나지 않는다. 즉 이 알고리즘으로 문제를 해결할 수 없고 다른 알고리즘을 찾아야 한다.

 

선형 회귀

이제 선형회귀 알고리즘을 쓸 타이밍인데 이름에서 알 수 있듯이 직선을 찾는 알고리즘이다.

사용법은 다른 알고리즘과 동일한데 50cm 농어 대해 1241g이라고 k-최근접 알고리즘 값 1033g 보다 높게 예측했다.

그럼 아까 위에서 얘기한 직선의 데이터도 얻을수 있는데

결정계수 값(R^2) 점수를 확인해보면

훈련세트에 과대적합? 훈련세트 점수 낮음? 등등의 여러 이상한점이 있는데

 

이 값으로 그래프를 그려보면

이제 제대로 예측한거 같긴한데 뭔가 좀 찜찜함... 산점도의 최소값 밑으로 직선의 그래프가 향해있는걸 알 수 있는데 무게가 0g 이하로 내려가는건 현실에선 있을수 없는일이다. 즉 직선보다는 최소값에서 시작해서 부드럽게 커브를 그리면서 올라가는 2차 방정식의 그래프가 필요하다.

 

이런식의 2차 방정식의 그래프를 그릴려면 길이를 제곱한 항이 훈련세트에 추가되어야 한다. 준비하고 훈련까지 시켜보자

위에서 구항 다항식의 기울기를 출력하면 다음과 같은데

요건 다음과 같이 해석된다고 함.

이렇게 다항식을 사용한 선형회귀를 다항회귀라고 한다. 이제 다시 그래프를 그려보면

직선보다 훨씬 나은 그래프가 그려졌고 무게가 음수로 나올 일도 없을 것이다. 결정계수 점수도 출력해보면 전보다 크게 높아진걸 알수 있다.

 

최종 코드

## k-최근접 이웃 회귀
### 데이터 준비

import numpy as np

perch_length = np.array(
    [8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0,
     21.0, 21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5,
     22.5, 22.7, 23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5,
     27.3, 27.5, 27.5, 27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0,
     36.5, 36.0, 37.0, 37.0, 39.0, 39.0, 39.0, 40.0, 40.0, 40.0,
     40.0, 42.0, 43.0, 43.0, 43.5, 44.0]
     )
perch_weight = np.array(
    [5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0,
     110.0, 115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0,
     130.0, 150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0,
     197.0, 218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0,
     514.0, 556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0,
     820.0, 850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0,
     1000.0, 1000.0]
     )

### 추세 파악

import matplotlib.pyplot as plt
plt.scatter(perch_length, perch_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

### 훈련세트, 테스트세트로 나누고 2차원 배열로 변환

from sklearn.model_selection import train_test_split

# 훈련 세트와 테스트 세트로 나눕니다.
train_input, test_input, train_target, test_target = train_test_split(
    perch_length, perch_weight, random_state=42
)

# 훈련 세트와 테스트 세트를 2차원 배열로 바꿉니다.
train_input = train_input.reshape(-1, 1)
test_input = test_input.reshape(-1, 1)


### 결정계수

from sklearn.neighbors import KNeighborsRegressor

knr = KNeighborsRegressor(n_neighbors=3)

# k-최근접 이웃 회귀 모델을 훈련합니다.
knr.fit(train_input, train_target)

print(knr.score(test_input, test_target))

### 수상한 농어(길이가 50cm)의 무게를 예측하고 패턴살펴보기

print(knr.predict([[50]]))

import matplotlib.pyplot as plt

# 50cm 농어의 이웃을 구합니다.
distance, indexes = knr.kneighbors([[50]])

# 훈련 세트의 산점도를 그립니다.
plt.scatter(train_input, train_target)

# 훈련 세트 중에서 이웃 샘플만 다시 그립니다.
plt.scatter(train_input[indexes], train_target[indexes], marker='D')

# 50cm 농어 데이터
plt.scatter(50, 1033, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

print(np.mean(train_target[indexes]))

print(knr.predict([[50]]))
print(knr.predict([[100]]))
print(knr.predict([[150]]))
print(knr.predict([[200]]))

# 100cm 농어의 이웃을 구합니다.
distance, indexes = knr.kneighbors([[100]])

# 훈련 세트의 산점도를 그립니다.
plt.scatter(train_input, train_target)

# 훈련 세트 중에서 이웃 샘플만 다시 그립니다.
plt.scatter(train_input[indexes], train_target[indexes], marker='D')

# 50cm 농어 데이터
plt.scatter(100, 1033, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

## 선형 회귀

from sklearn.linear_model import LinearRegression

lr = LinearRegression()

# 선형 회귀 모델을 훈련합니다.
lr.fit(train_input, train_target)

print(lr.score(test_input, test_target))

# 50cm 농어 대해 예측합니다.
print(lr.predict([[50]]))

print('기울기:', lr.coef_, '절편:', lr.intercept_)

# 훈련 세트의 산점도를 그립니다.
plt.scatter(train_input, train_target)

# 15에서 50까지 1차 방정식 그래프를 그립니다.
plt.plot([15,50], [15*lr.coef_ + lr.intercept_, 50*lr.coef_ + lr.intercept_])

# 50cm 농어 데이터
plt.scatter(50, 1241, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

print(lr.score(train_input, train_target)) # 훈련세트
print(lr.score(test_input, test_target)) # 테스트 세트

### 2차 방정식 준비

train_poly = np.column_stack((train_input ** 2, train_input))
test_poly = np.column_stack((test_input ** 2, test_input))

print(train_poly.shape, test_poly.shape)

lr = LinearRegression()

lr.fit(train_poly, train_target)

print(lr.predict([[50**2, 50]]))

print('기울기:', lr.coef_, '절편:', lr.intercept_)

# 구간별 직선을 그리기 위해 15에서 49까지 정수 배열을 만든다.
point = np.arange(15, 50)
print(point)

# 훈련 세트의 산점도를 그린다.
plt.scatter(train_input, train_target)

# 15에서 49까지 2차 방정식 그래프를 그린다.
plt.plot(point, 1.01*point**2 - 21.6*point + 116.05)

plt.scatter([50], [1573], marker='^')

plt.show()

print(lr.score(train_poly, train_target)) # 훈련세트
print(lr.score(test_poly, test_target)) # 테스트 세트

'AI > 혼자 공부하는 머신러닝+딥러닝 책' 카테고리의 다른 글

챕터 04 - 1  (0) 2023.07.17
챕터 03 - 3  (0) 2023.07.15
챕터 03 - 1  (0) 2023.07.10
챕터 02 - 2  (1) 2023.07.08
챕터 02 - 1  (0) 2023.07.06