-
[혼공머] 3-3. 특성 공학과 규제Data Science/딥러닝 & 머신러닝 2025. 1. 10. 23:49
1. 배경
1. 적은 특성 사용 및 고차항 사용
- 수동으로 고차항을 계속 넣기는 어렵다는 문제
- 특성이 많을수록 효과가 커진다.
2. 선형 회귀 모델의 학습
-
- 1개의 특성 → 직선
- 2개의 특성 → 평면
- 인간은 3차원 공간 이상을 그리거나 상상할 수 없다.선형 회귀
- 3차원 이상의 고차원 : 매우 복잡한 모델을 표현할 수 있다.
2. 다중 회귀와 특성 공학
1. 다중 회귀
- 여러 개의 특성을 사용한 선형 회귀
- 선형 회귀와의 차이
- 선형 회귀 : 1개의 특성, 직선 학습
- 다중 회귀 : 여러 개의 특성, 평면 학습
- 다항 회귀와의 차이 *
- 다항 회귀 : 1개의 독립 변수를 비선형적으로 변형해서 여러 개로 사용
- ex. y=β_0 + β_1x + β_2x^2 +⋯+ϵ.
- 다중 회귀 : 여러 독립 변수를 사용
- ex. y=β_0 + β_1x1 + β_2x2 +⋯+ϵ.
2. 특성 공학
- 기존의 특성을 사용해 새로운 특성을 뽑아내는 작업
- 목적 : 존의 데이터로부터 유용한 정보를 추출하거나 데이터를 변환하여 모델의 성능을 향상시키는 것
- ex. 기존 변수인 lengh, weight 를 이용해 새로운 변수 length*weight 생성
3. 데이터 준비
1. 데이터프레임
- csv 파일을 이용한다.
- 순서
- pandas의 read_csv()
- to_numpy()
2. 훈련 데이터와 타겟 데이터 준비
import pandas as pd df = pd.read_csv('<https://bit.ly/perch_csv_data>') perch_full = df.to_numpy() 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] )
3. 훈련 세트와 테스트 세트 분할
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)
4. 사이킷런의 변환기
1. 변환기
- 특성을 만들거나 전처리하기 위한 클래스
- fit, transform 메서드 제공
2. PolynomialFeatures
- 교재에서는 PolynomialFeatures 클래스 사용from sklearn.preprocessing import PolynomialFeatures
- 순서
- fit
- transform : 훈련해야 변환이 가능하다.
- 특성 자체, 특성끼리 곱한 값, 각 특성의 제곱, 1이 된다
- 1 은 절편 값
- 순서
- include_bias = False
- 사이킷런의 선형 모델은 자동으로 절편 추가해서, 절편값인 1이 따로 필요하지 않다.
poly = PolynomialFeatures(include_bias=False) poly.fit([[2, 3]]) print(poly.transform([[2, 3]])) # [[2. 3. 4. 6. 9.]]
# 예시 from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures() poly.fit([[2, 3]]) print(poly.transform([[2, 3]])) # [[1. 2. 3. 4. 6. 9.]]
5. 다중 회귀 모델 훈련
1. train_input, test_input 에 적용
poly = PolyNomialFeatures(include_bias=False) ploy.fit(train)input) train_poly = poly.transform(train_input) test_poly = poly.transform(test_input) print(train_poly.shape) # (42, 9)
- get_features_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)
2. 다중 회귀 모델 훈련하기
- 선형 회귀 모델을 훈련하는 것과 같다.
from sklearn.linear_model import LinearRegression lr = Linear_regression() lr.fit(train_poly, train_target)
3. 모델의 정확도
print(lr.score(train_poly, train_target)) # 0.99 print(lr.score(test_poly, test_target)) # 0.97
과소적합 문제는 해결되었음!
4. 특성을 추가한 모델 재훈련
- 더 높은 제곱의 항 추가
- PolunomialFeatures 클래스의 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) # 모델 훈련과 점수 lr.fit(train_poly, train_target) lr.score(train_poly, train_target) # 0.99 lr.score(test_poly, test_target) # -144.4
훈련 세트에 너무 과대적합되므로 테스트 세트에서 점수가 음수 나옴.
→ 특성을 다시 줄여야 한다.
6. 규제
1. 규제의 정의
- 머신러닝 모델이 훈련 세트를 과도하게 학습하지 못하도록 훼방하는 것
- 모델이 훈련 세트에 과대적합되지 않도록 만드는 것
- 선형 회귀 모델에서는, 기울기 (계수) 작게 만드는 것
2. 규제 이전에 꼭 해야 하는 것 : 표준화
- 이유 : 계수값에 차이가 나면 공정하게 제어되지 않을 수 있기 때문이다.
- mean, std 구해서 하지 말고, 사이킷런의 StandardScaler 클래스를 사용한다.
- 순서
- StandardScaler 클래스의 객체 ss 초기화
- PolynomialFeatures 클래스로 만든 train_poly를 사용해 객체 훈련
- 훈련 세트로 학습한 변환기를 사용해 테스트 세트까지 반환
from sklearn.preprocessing import StandardScaler ss = StandardScaler() ss.fit(train_poly) train_scaled = ss.transform(train_poly) test_scaled = ss.transform(test_poly)
- 선형 회귀 모델에 규제를 추가한 모델
- 둘 다 같은 패키지 안에 있다.
- 릿지 : 계수를 제곱한 값을 기준으로 규제 적용
- 라쏘 : 계수의 절댓값을 기준으로 규제 적용; 계수 크기를 0으로 만들 수도 있다.
- 하이퍼파라미터 : 사람이 알려줘야 하는 파라미터
3. 릿지 회귀
from sklearn.linear_model import Ridge ridge = Ridge() ridge.fit(train_scaled, train_target) print(ridge.score(train_scaled, train_target)) # 0.98 print(ridge.score(test_scaled, test_target)) # 0.97
너무 과대적합되지 않아 테스트 성능에서도 좋은 성능을 낸다.
- alhpa 값의 변경
- 줄이면 과대적합 가능성 증가 : 규제 강도 감소
- 높이면 과소적합 가능성 증가 : 규제 강도 증가
- 적절한 alhpa 값 : 훈련 세트와 테스트 세트의 점수가 가장 가까운 지점
- alpha 값 찾기
import matplotlib.pyplot as plt train_score = [] test_score = [] # alpha 바꿀 때마다 score()한 값 저장할 리스트 alpha_list = [0.001, 0.01, 0.1, 1, 10, 100] # 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)) # 그래프 그리기 : 동일 간격을 위해 지수로 표현 (상용로그) plt.plot(np.log10(alpha_list), train_score) # blue plt.plot(np.log10(alpha_list), test_score) # oragne plt.xlabel('alpha') plt.ylabel('R^2')
2. alpha =0.1로 훈련ridge = Ridge(alpha=0.1) ridge.fit(train_scaled, train_target) print(ridge.score(train_scaled, train_target)) # 0.99 print(ridge.score(test_scaled, test_target)) # 0.98
- 가장 가까운 alhpa = orange 에서 가장 높은 -1 = 0.1
4. 라쏘 회귀
- 계수의 크기를 0으로 만들 수도 있다.
from sklearn.linear_model import Lasso lasso = Lasso() lasso.fit(train_scaled, train_target) print(lasso.score(train_scaled, train_target)) # 0.98 print(lasso.score(test_scaled, test_target)) # 0.97
- 적절한 alpha 값 찾기 : 훈련 세트와 테스트 세트의 점수가 가장 가까운 지점
- alpha 값 찾기
import matplotlib.pyplot as plt train_score = [] test_score = [] # alpha 바꿀 때마다 score()한 값 저장할 리스트 alpha_list = [0.001, 0.01, 0.1, 1, 10, 100] # alpha 값 리스트 for alpha in alpha_list: lasso = Lasso(alpha=alpha) # 모델 생성 lasso.fit(train_scaled, train_target) # 훈련 # 훈련 세트와 테스트 세트의 점수 각각 저장 train_score.append(lasso.score(train_scaled, train_target)) test_score.append(lasso.score(test_scaled, test_target)) # 그래프 그리기 : 동일 간격을 위해 지수로 표현 (log10) plt.plot(np.log10(alpha_list), train_score) # blue plt.plot(np.log10(alpha_list), test_score) # oragne plt.xlabel('alpha') plt.ylabel('R^2')
2. alpha =10로 훈련
lasso = Lasso(alpha=10) lasso.fit(train_scaled, train_target) print(lasso.score(train_scaled, train_target)) # 0.988 print(lasso.score(test_scaled, test_target)) # 0.982
7. 모델의 과대적합 제어하기 전체 소스 코드
# 훈련 데이터 df = pd.read_csv('<https://bit.ly/perch_csv_data>') perch_full = df.to_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) # 사이킷런 변환기로 다중 회귀 특성 만들기 from sklearn.preprocessing import PolynomialFeatures 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)) # 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) lr.score(train_poly, train_target) lr.score(test_poly, test_target) # 규제를 위한 표준화 과정 from sklearn.preprocessing import StandardScaler ss = StandardScaler() ss.fit(train_poly) train_scaled = ss.transform(train_poly) test_scaled = ss.transform(test_poly) # 릿지 회귀 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)) # 최적의 alpha 를 이용한 릿지 회귀 # 1. alpha 찾기 import matplotlib.pyplot as plt train_score = [] test_score = [] 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.xlabel('alpha') plt.ylabel('R^2') plt.show() # 2. alpha로 재훈련 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)) ## # 라쏘 회귀 from sklearn.linear_model import Lasso lasso = Lasso() lasso.fit(train_scaled, train_target) print(lasso.score(train_scaled, train_target)) print(lasso.score(test_scaled, test_target)) # 최적의 alpha 를 이용한 라쏘 회귀 # 1. alpha 찾기 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) 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) # blue plt.plot(np.log10(alpha_list), test_score) # oragne plt.xlabel('alpha') plt.ylabel('R^2') # 2. alpha로 재훈련 lasso = Lasso(alpha=10) lasso.fit(train_scaled, train_target) print(lasso.score(train_scaled, train_target)) print(lasso.score(test_scaled, test_target)) # 3. 계수 0인 특성의 개수 print(np.sum(lasso.coef_==0))
'Data Science > 딥러닝 & 머신러닝' 카테고리의 다른 글
[혼공머] 4-2. 확률적 경사 하강법 (0) 2025.01.11 [혼공머] 4-1. 로지스틱 회귀 (0) 2025.01.10 [혼공머] 3-2. 선형 회귀 (0) 2025.01.10 [혼공머] 3-1. K-최근접 이웃 회귀 (0) 2025.01.10 [혼공머] 2-2. 데이터 전처리 (0) 2025.01.10