Feature enginerring(특성공학): 기존 특성, 데이터를 바탕으로 새로운 특성을 만드는 작업
이번엔 데이터를 파일에 근거해서 불러온다(pandas)
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
mpl.rcParams['font.family'] = 'Malgun Gothic' # 그래프에 한글 설정
mpl.rcParams['axes.unicode_minus'] = False # 그래프에 마이너스 기호 깨지는 문제 해결
df = pd.read_csv('https://bit.ly/perch_csv') # length, height, width 3열로 된 데이터이다.
perch_full = df.to_numpy() # df -> numpy 배열로 변환
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_full, perch_weight, random_state=42)
데이터 준비, 훈련, 테스트 셋 분리 내용이다.
PolynomialFeatures()로 다항식을 바로 만들 수 있다.
특성 (예제)
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures() # 객체화하고
poly.fit([[2, 3]]) # 학습할 데이터를 fit 안에 리스트로 넣어준다.
print(poly.transform([[2, 3]])) # 그리고 transform으로 변형 확정을 한다.
[[1. 2. 3. 4. 6. 9.]] <- 기본 1 곱셈, 원본 2, 원본 3, 2의 2 * 2, 2 * 3, 3 * 3. <- 이렇게 구성되어서 다항식을 만든다.
사이킷런 Linear model은 자동 절편 추가 有이므로 1(자동 절편항)을 생략하려면 다음과 같이 작성한다.
물론 1이 있어도 사이킷런은 자동절편을 무시하긴 하지만 여기선 혼돈 피하기위해 명시적 표현함
include_bias = False 옵션 활성화
poly = PolynomialFeatures(include_bias=False) #1을 생략
poly.fit([[2, 3]]) # 학습할 데이터를 fit 안에 리스트로 넣어준다.
print(poly.transform([[2, 3]])) # 그리고 transform으로 변형 확정을 한다.
[[2. 3. 4. 6. 9.]]
어떻게 해당 자료가 형성되었는지 호출하는 함수 poly.get_feature_names_out()
poly.get_feature_names_out()
array(['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2', 'x2^2'], dtype=object)
데이터에 적용하자
poly = PolynomialFeatures(include_bias=False) # 객체화
poly.fit(train_input) # 훈련 데이터 대입
train_poly = poly.transform(train_input) # 훈련 변형 적용
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)) # 정확도 검증
print(lr.score(test_poly, test_target))
0.9903183436982124
0.9714559911594134
확실히 특성 추가로 인해 정확도가 올라갔다.
더 추가하려면? degree를 통해 최고차항을 지정한다.
poly = PolynomialFeatures(degree=5, include_bias=False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))
0.9999999999991098 <- 확실히 훈련 세트 정확도는 높아졌지만
-144.40579242684848 <- 지나친 overfitting이므로 테스트에서는 음수가 출력되었다. 형편없는 결과!
print(train_poly.shape)
(42, 55) 전체 데이터 42에서 만들어진 특성 개수가 55개이다. 데이터 < 특성개수 이므로 overfitting은 당연한 결과!
이 overfitting 문제를 어떻게 해결해야할까?
regulation(규제): 머신러닝 과도학습 훼방법. linear에서는 특성 계수 작게 만들기. 보통 Ridge, Lasso로 한다.
Ridge regression: 계수 제곱값을 기준으로 규제 적용 (Lasso보다 더 많이 쓰임)
Lasso regression: 계수 절댓값을 기준으로 규제 적용 (0으로 만들 수도 있음)
현재 특성이 여러개이므로 모두 다 표준화를 해야한다. StandardScaler를 사용하여 기본세팅을 만들자.
from sklearn.preprocessing import StandardScaler
ss = StandardScaler() # 객체화
ss.fit(train_poly) # 훈련; 문제의 5차 과적합 data이다.
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly) # 변형 적용
해당 data는 모두 [0, 1] 에서 값이 재설정되었다.
Ridge (계수 제곱값 기준)
from sklearn.linear_model import Ridge
ridge = Ridge() # 객체화
ridge.fit(train_scaled, train_target) # 훈련(대상 데이터 대입)
print(ridge.score(train_scaled, train_target)) # 평가
print(ridge.score(test_scaled, test_target))
0.9896101671037343 <- train 정확도가 내려갔지만
0.9790693977615398 <- test의 음수 상태가 해결되었다.
ridge와 lasso는 alpha 값 수정을 통해 규제 강도 조절 可 <- 자동 최적이 아니고 사람이 지정해야함(hyperparameter)
alpha값이 크면 규제가 크고 작으면 작다.
최적 alpha값을 찾으려면? -> 결정계수(R2) 그래프 그려본다.
import matplotlib.pyplot as plt
train_score = []
test_score = [] # score() 결과를 저장할 list 정의
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100] # 10배 단위로 바뀌는 alpha값
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)) # list에 값 저장 append 함수
plt.plot(np.log10(alpha_list), train_score) #상용로그 np.log10()로 값을 받아야한다.
plt.plot(np.log10(alpha_list), test_score) # 0.003 -> -3, 0.01 -> -2로 출력됨
plt.legend(['Train score', 'Test score'], loc = 'best')
plt.show()
이 그래프 결과에 따르면 -1(alpha = 0.1) 일 때test score 점수가 제일 좋다.
0.1로 최종 훈련해보자.
ridge = Ridge(alpha=0.1)
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
print(ridge.score(test_scaled, test_target))
0.9903815817570368
0.9827976465386954
train > test 이면서 둘 다 정확도가 높게 나왔다!
Lasso (계수 절댓값 기준)
from sklearn.linear_model import Lasso # ridge와 코드 작성방식은 동일하다. 이름만 바뀜
lasso = Lasso()
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))
0.989789897208096
0.9800593698421884
default 결과도 ridge default만큼 결과가 좋다. alpha값도 찾아보자 (코드 동일. lasso로 이름만 바뀜)
train_score = []
test_score = []
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
lasso = Lasso(alpha=alpha, max_iter=10000) # max_iter: 지정 반복횟수 설정. 기본값은 1000
lasso.fit(train_scaled, train_target) # 이 반복횟수가 부족하면 convergence warning 뜸.
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.legend(['Train score', 'Test score'], loc = 'best')
plt.show()
여기서 최적 alpha = 10 (1값)이다. 반영해보자
lasso = Lasso(alpha=10)
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))
0.9888067471131867
0.9824470598706695 -> 앞선 결과보다 훈련 값은 떨어지면서 test값 상승, 그러나 과적합은 피하였다.
Lasso가 0으로 만든 계수는 총 몇 개인지 알아보자
print(np.sum(lasso.coef_ == 0)) # np.sum()은 True = 1, False = 0 으로 덧셈이 可
40 <- 55개 특성중 40개가 0이 되버렸다! 즉, lasso가 사용한 특성은 15개 뿐이다.
이와같이 lasso는 유용한 특성이 무엇인지 골라내는 용도로 사용되기도 한다.
'Programming > Python' 카테고리의 다른 글
[DL] tensorflow, Deep Neural Network(DNN) (0) | 2023.09.15 |
---|---|
[Numpy] Linear algebra package (0) | 2023.09.13 |
[ML] KN 회귀 알고리즘, 선형회귀, 다항회귀 (0) | 2023.09.11 |
[ML] KN 분류 알고리즘 (실전편) (0) | 2023.09.11 |
[ML] KN 분류 알고리즘 (기본편) (0) | 2023.09.11 |