본문 바로가기

KHUDA

KHUDA ML세션 2주차

회귀 알고리즘과 모델 규제 

 

chapter 3-1 k-최근접 이웃 회귀 

회귀(regression)는 임의의 두 숫자를 예측

ex)내년도 경제성장률, 농어의 무게 예측

 

k-최근접 이웃 회귀 

k-최근접이웃 회귀

분류와 같이 k개를 선택 하지만 회귀이기 때문에 이웃한 샘플의 타깃은 어떤 클래스가 아니라 임의의 수치이다.

ex) 타깃값 100,80,60일때 예측 타깃값은 80이다. 

 

import numpy as np
import matplotlib.pyplot as plt

#데이터 준비
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])

#산점도 그리기
plt.scatter(perch_length, perch_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show(

 

사이킷런에서 활용되는 훈련 세트는 2차원 배열이어야 한다. 

reshape() 매서드를 활용해서 배열 크기 바꾸기
 
test_array = np.array([1,2,3,4])
print(test_arrat.shape)

test_array = test_array.reshape(2,2)
print(test_array.shape)
훈련 세트와 테스트 세트 배열 바꾸기 

넘파이 배열 크기 자동 지정 

ex) 첫번째 크기를 나머지 원소 개수로 채우고, 두번쨰 크기를 1로 하려면 train_input.reshape(-1,1)

train_input = train_input.reshape(-1,1)
test_input = test_input.reshape(-1,1)
print(train_input.shape, test_input.shape) 
k-최근접 이웃 회귀 알고리즘 구현 

클래스 : KNeighborsRegressor

from sklearn.neighbors import KNeighborsRegressor

knr = KNeighborsRegressor()
#k-최근접 이웃 회귀 모델 훈련
knr.fit(train_input, train_target)

#테스트 세트 점수 확인
print(knr.score(test_input, test_target)) #결괏값 : 0.992809406101064

 test set 점수는 정확도라고 할 수 있다. 

회귀에서 정확한 숫자를 맞힌다는 것은 불가능 하기 때문이다. 

예측하는 값이나 타깃 모두 임의의 수치이기 떄문

결정계수coefficient of determination)

타깃이 평균 정도를 예측하는 수준이라면 결정계수는 0에 가까워 지고, 예측이 아주 가까워 지면 1에 가까운 값이 됩니다. 

절댓값 오차 구하기 
from sklearn.metrics import mean_absolute_error

#테스트 세트에 대한 예측 만들기
test_prediction = knr.predict(test_input)

#테스트 세트에 대한 평균 절댓값 오차 계산하기
mae = mean_absolute_error(test_target, test_prediction)
print(mae) #결괏값 : 19.157142857142862

평균적으로 19g 정도 타깃값과 다르다고 할 수 있다. 

과소적합 : 훈련세트 점수 >>>>>>> 테스트 세트 점수 (새로운 예측 x)
과대적합 : 테스트 세트 점수 >>>>>> 훈련세트 점수 or 둘 다 낮을때 (모델이 너무 단순하여 훈련 세트가 적절히 훈련되지 않은 경우  )
과소적합, 과대적합을 해결하는 방법
과소적합 해결하기
→ 모델을 더 복잡하게 만들어야 함. = k 줄이기
과대적합 해결하기
→ 모델을 덜 복잡하게 만들어야 함. = k 늘리기
k 감소 : 훈련세트 패턴에 민감해짐
k 증가 : 데이터 전반적인 패턴에 따름 
#이웃의 개수 3으로 설정
knr.n_neighbors = 3

#모델 다시 훈련하기
knr.fit(train_input, train_target)

#훈련 세트 점수 확인
print(knr.score(train_input, train_target)) #결괏값 : 0.9804899950518966

#테스트 세트 점수 확인
print(knr.score(test_input, test_target)) #결괏값 : 0.9746459963987609

 

 

chapter 3-2 선형 회귀

k-최근접 이웃 알고리즘의 한계
데이터 준비
import numpy as np
import matplotlib.pyplot as plt

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])

#훈련 / 테스트 세트 나누기
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)

#이웃 개수를 3으로 하는 모델 훈련하기
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor(n_neighbors = 3)

#k-최근접 이웃 회기 모델 훈련
knr.fit(train_input, train_target)
 
 
 
 
길이가 50cm 인 농어의 무게
print(knr.predict([[50]])) #결괏값 : [1033.33333333]
가장 가까운 이웃 구하기 
#50cm 농어의 이웃 구하기
distances, 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.show()

길이가 50cm의 농어에서 가장 가까운 이웃은 45cm 근방이기 때문에

k-최근접 이웃 알고리즘은 이 샘플들의 무게를 평균하여 엉뚱한 값을 예측함 

 

 

선형 회귀 linear regression

특성이 하나인 경우 어떤 직선을 학습하는 알고리즘

LinearRession class

from sklearn.linear_model import LinearRegression
lr = LinearRegression()

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

#50cm 농어에 대한 예측
print(lr.predict([[50]])) #결괏값 : [1241.83860323]

기울기(a)와 절편(b)은 각각 lr 객체의 coef와 intercept 속성에 저장되어 있음.

print(lr.coef_, lr.intercept_)
#결괏값 : [39.01714496] -709.0186449535477
모델 파라미터 
coef_와 intercept_를 머신러닝 알고리즘이 찾은 값이라는 의미로 모델 파라미터 라고 부른다 
머신러닝 훈련과정을 최적의 모델 파라미터를 찾는 것과 같다. 이를 모델 기반 학습이라고 한다. 
k-최근접 이웃에는 모델 파라미터가 없다 이를 사례 기반 학습이라고 한다. 
산점도 직선으로 표현하기 
#훈련 세트의 산점도 그리기
plt.scatter(train_input, train_target)

#15 - 50까지의 1차 방정식 그래프 그리기
plt.plot([15, 50], [15*lr.coef_ + lr.intercept_, 50*lr.coef_ + lr.intercept_])
# (x1,x2) , (y1, y2) 연결

#50cm 농어 데이터
plt.scatter(50, 1241.8, marker='^')
plt.show()

최적의 직선

결정계수 파악하기 
#훈련세트
print(lr.score(train_input, train_target)) #결괏값 : 0.939846333997604

#테스트세트
print(lr.score(test_input, test_target))  #결괏값 : 0.8247503123313558

전체적인 과소 적합 

 

다항회귀 
다항회귀 : 다항식을 사용하여 특성과 타깃 사이의 관계를 나타냅니다. 이 함수는 비선형일 수 있지만 여전히 선형 회귀로 표현할 수 있습니다. 

다항회귀는 곡선의 형태를 이루고 있음 

길이를 제곱한 항을 훈련 세트에 추가 column_stack() 함수 사용 

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) #결괏값 : (42, 2) (14, 2)

선형 회귀 모델 재학습 
#길이 제곱한 항 훈련
lr = LinearRegression()
lr.fit(train_poly, train_target)

#예측값
print(lr.predict([[50**2, 50]])) #결괏값 : [1573.98423528]

#기울기와 절편 출력 (a, b, c)
print(lr.coef_, lr.intercept_) #결괏값 : [  1.01433211 -21.55792498] 116.0502107827827
산점도 그리기 
#산점도 그리기

#구간별 직선을 그리기 위해 15 - 49 정수 배열 만들기
point = np.arange(15,50)
#훈련 세트 산점도 그리기
plt.scatter(train_input, train_target)

#15 - 49까지 2차 방정식 그래프 그리기
plt.plot(point, 1.01*point**2 - 21.6*point + 116.05)

#50cm 농어 데이터
plt.scatter([50], [1574], marker='^')
plt.show()

선형 회귀로 훈련세트 범위 밖의 샘플 예측 

 

chapter 3-3 특성 공학과 규제

선형,다항회귀의 문제점

: 다항회귀로도 여전히 훈련 > 테스트 세트 점수인 과소 적합 발생

해결법

선형 회귀는 특성이 많을 수록 효과가 좋기 때문에 높이와 두꼐를 다항회귀에 적용

 

다중회귀(multiple regression)
여러개의 특성을 사용한 선형 회귀 

3차원 이상에 차원은 우리가 상상할 수 없으므로 높이, 두께, 길이, 무게 등 특성이 있을때 높이x두꼐를 통해 새로운 특성을 만드는 것을 특성 공학이라고 한다. 

데이터 준비

pandas 라이브러리 사용 

데이터 프레임은 판다스의 핵심 데이터 구조이다. 

import pandas as pd #판다스 라이브러리 임포트
df = pd.read_csv('https://bit.ly/perch_csv') #read_csv('링크') = 파일 불러오기
perch_full = df.to_numpy() #넘파이로 변환
print(perch_full)
#타깃데이터 준비
import numpy as np
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])

#perch_full(특성)과 perch_weight(타킷) 훈련 / 테스트 세트로 나누기
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(perch_full, perch_weight, random_state=42)
변환기

사이킷런에서 특성을 만들거나 전처리하기 위해 다양한 클래스를 제공. 

이런 클래스를 변환기라고 부름.

fit() : 새롭게 만들 특성 조합 찾기

transform() : 실제 데이터로 변환

#클래스 임포트
from sklearn.preprocessing import PolynomialFeatures
#클래스 객체 생성
poly = PolynomialFeatures()

#모델 훈련 - 2개의 특성 '2와 3'으로 이루어진 샘플 적용
poly.fit([[2, 3]])
#변환
print(poly.transform([[2, 3]])) #결괏값 : [[1. 2. 3. 4. 6. 9.]] 훈련을 해야 변환이 가능하다.
훈련을 해야 변환이 가능하다
변환기는 입력데이터를 변환하는데 타깃데이터가 필요하지 않다,
샘플[2,3]이 샘플 [1,2,3,4,6,9]으로 바뀌었음  

PolynomialFeatures 클래스는 기본적으로 각특성을 제곱한 항을 추가하고 특성끼로 서로 곱한 항을 추가

2와 3을 제곱한 4와 9, 2와 3을 제곱한 6이 추가되었다.

여기서 1은 선형 방정식의 절편을 항상 값이 1인 특성과 곱해지는 계수이다. 

특성  =  ( 길이, 높이, 두께,1)

 

사이킷런에선 자동으로 특성에 추가된 절편항을 무시, 따라서 include _bias = False를 추가할 필요가 없다. 

poly = PolynomialFeatures(include_bias = False)
poly.fit([[2, 3]])
print(poly.transform([[2, 3]])) #[[2. 3. 4. 6. 9.]]
poly.fit(train_input)
train_poly = poly.transform(train_input)
#배열 크기 확인
print(train_poly.shape) #결괏값 : (42, 9)

#특성의 입력 조합 확인
poly.get_feature_names() #결괏값 : ['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2', 'x2^2']

#테스트 세트 변환
test_poly = poly.transform(test_input)

훈련세트에 적용했던 변환기로 테스트 세트를 변환하는것이 중요하다.

다중 회귀 모델 훈련하기 
#선형 회귀 모델 임포트
from sklearn.linear_model import LinearRegression
#객체 생성
lr = LinearRegression()
#학습
lr.fit(train_poly, train_target)
#평가- 훈련 세트
print(lr.score(train_poly, train_target)) #결괏값 : 0.9903183436982125
#평가 - 테스트 세트
print(lr.score(test_poly, test_target)) #결괏값 : 0.9714559911594111

과소적합의 문제 해결 

더 많은 특성 추가하기 
매개변수 degree : 고차항의 최대 차수를 지정하는 매개변수  
#최대차항 5차항으로 설정
poly = PolynomialFeatures(degree=5, include_bias=False)

poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)

#열(특성) 개수 확인
print(train_poly.shape) #결괏값 : (42, 55)

특성의 개수 =  열의 개수  = 55

선형 회귀 모델 재훈련
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target)) #결괏값 : 0.9999999999996433
print(lr.score(test_poly, test_target)) #결괏값 : -144.40579436844948

테스트 세트의 점수가 큰 음수로 나옴. 

 

특성의 개수를 크게 늘리면 선형 모델은 정확해짐
하지만, 과대적합 되므로 테스트 세트에서는 형편 없는 점수를 만듬

 

규제(Regularization)
머신러닝 모델이 훈련 세트를 너무 과도하게 학습하지 못하도록 훼방하는 것을 말한다.
선형 회귀 모델에 경우 기울기의 크기를 작게 만듦.  

                             과도한 특성 학습                                                                       기울기를 줄여 보편적인 패턴 학습

규제에 적용될 계사 값의 크기를 맞춰 공정하게 제어하기 위해 정규화를 시행

정규화
StandardScaler class사용
#표준점수로 변환해주는 클래스 StandardScler 임포트
from sklearn.preprocessing import StandardScaler

#객체 초기화
ss = StandardScaler()

#훈련
ss.fit(train_poly)

#변환
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)
릿지 회귀(ridge) 
계수를 제곱한 값을 기준으로 규제함
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target)) #결괏값 : 0.9896101671037343
alpha (매개변수)
릿지, 라쏘 델의 규제의 양을 조절하는 매개변수 
alpha 작음
계수 줄이도록 함 줄임을 낮춤
모델 과소적합 유도 과대적합 유도 
적합한 alpha 찾기 
import matplotlib.pyplot as plt

#alpha 값을 바꿀 때마다 score의 결괏값을 저장할 리스트 생성
train_score = []
test_score = []

#알파 값 리스트 - 10배씩 늘림
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]

for alpha in alpha_list:
  #릿지 모델 생성
  ridge = Ridge(alpha=alpha)
  #릿지 모델 훈련
  ridge.fit(train_scaled, train_target)
  #훈련 점수와 테스트 점수 저장
  train_score.append(ridge.score(train_scaled, train_target))
  test_score.append(ridge.score(test_scaled, test_target))
plt.plot(np.log10(alpha_list), train_score)
plt.plot(np.log10(alpha_list), test_score)
plt.show

적절한 alpha 값은 두 그래프가 가장 가깝고 테스트 세트 점수가 가장 높은 -1 즉 0.1이다

 

라쏘 회귀
릿지 회귀와 유사, Lasso 클래스로만 바꾸면 된다. 
라쏘 모델에서 적합한 alpha 찾기 
import matplotlib.pyplot as plt

#alpha 값을 바꿀 때마다 score의 결괏값을 저장할 리스트 생성
train_score = []
test_score = []

#알파 값 리스트 - 10배씩 늘림
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]

for alpha in alpha_list:
  #라쏘 모델 생성
  lasso = Lasso(alpha=alpha, max_iter=10000)
  #라쏘 모델 훈련
  lasso.fit(train_scaled, train_target)
  #훈련 점수와 테스트 점수 저장
  train_score.append(lasso.score(train_scaled, train_target))
  test_score.append(lasso.score(test_scaled, test_target))
plt.plot(np.log10(alpha_list), train_score)
plt.plot(np.log10(alpha_list), test_score)
plt.show()

 

'KHUDA' 카테고리의 다른 글

KHUDA Data buisness 01  (0) 2024.03.13
KHUDA ML 세션 5주차  (1) 2024.02.27
KHUDA ML 세션 4주차  (1) 2024.02.20
KHUDA ML세션 3주차  (1) 2024.02.13
KHUDA ML세션 1주차  (1) 2024.01.31