2023. 3. 7. 16:01ㆍ데이터 엔지니어링 과정/python
1. k-최근접 이웃 회귀
2. 선형 회귀
3. 특성 공학과 규제
1. k-최근접 이웃 회귀
1. k-최근접 이웃 회귀
- 지도 학습 알고리즘
- 분류
: 샘플을 몇 개의 클래스 중 하나로 분류 - 회귀
: 클래스 중 하나로 분류하는 것이 아니라 임의의 어떤 숫자 예측- k-최근접 이웃 알고리즘
: 예측하려는 샘플에 가장 가까운 샘플 k개를 선택
➡ 샘플들의 클래스 확인하여 다수 클래스를 새로운 샘플의 클래스로 예측 - k-최근접 이웃 회귀
: 예측하려는 샘플에 가장 가까운 샘플 k개 선택
➡ 이웃한 샘플들의 평균을 구해 수치 예측
- k-최근접 이웃 알고리즘
- 분류
2. 데이터 준비
💻 (농어 데이터) 훈련 데이터 준비 후 산점도
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()
💻 산점도에 표현
import matplotlib.pyplot as plt
plt.scatter(perch_length, perch_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
🔎 농어의 길이가 커짐에 따라 무게도 늘어남
💻 농어 데이터 머신러닝 모델에 사용하기 전에 훈련 세트와 테스트 세트로 나눔
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차원 배열이어야 함
📍 reshape() 메서드 : 크기에 -1 지정하면 나머지 원소 개수로 모두 채우라는 뜻
train_input = train_input.reshape(-1,1)
test_input = test_input.reshape(-1,1)
print(train_input.shape, test_input.shape)
>>> (42, 1) (14, 1)
3. 결정계수
📍 KNeighborsRegressor : 사이킷런에서 k-최근접 이웃 회귀 알고리즘을 구현한 클래스
💻 객체 생성 후 훈련
from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor()
# k-최근접 이웃 회귀 모델 훈련
knr.fit(train_input, train_target)
📌 결정계수 coefficient of determination : 타깃의 평균 정도를 예측하는 수준이라면 0에 가까워지고, 예측이 타깃에 가까워지면 2에 가까워짐
💻 테스트 점수 확인
knr.score(test_input, test_target)
>>> 0.992809406101064
4. 과대적합 vs 과소적합
💻 훈련한 모델을 활용하여 훈련 세트의 결정계수 점수 확인
knr.score(train_input, train_target)
>>> 0.9698823289099254
- 과대적합
: 훈련세트와 테스트 세트의 점수를 비교했을 때, 훈련 세트가 너무 높을 때 - 과소적합
: 훈련세트와 테스트 세트의 점수를 비교했을 때, 테스트 세트가 너무 높거나 두 점수가 모두 낮을 때
🔎 현재 데이터를 보면 test보다 train이 더 높다. 따라서 과소적합 상황이라고 판단할 수 있다.
📌 과소적합 해결하기 ➡ 이웃의 개수를 줄여 모델을 더 복잡하게 만들기
🔎 과대적합인 경우에는 반대로 이웃의 개수를 늘리면 돼!
# 이웃의 개수를 3으로 설정
knr.n_neighbors = 3
# 모델 훈련
knr.fit(train_input, train_target)
print(knr.score(train_input, train_target))
>>> 0.9804899950518966
💻 테스트 세트의 점수 확인
knr.score(test_input, test_target)
>>> 0.9746459963987609
2. 선형회귀
1. k-최근접 이웃의 한계
💻 50cm 농어의 무게와 100cm 농어의 무게 예측
print(knr.predict([[50]]))
print(knr.predict([[100]]))
>>> [1033.33333333]
>>> [1033.33333333]
💻 산점도에 표시
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.scatter(100, 1033, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
🔎 농어의 실제 무게는 예측값보다 많이 나간다. k-최근접 이웃 알고리즘은 샘플들의 무게를 평균화하기 때문에 1033이 최대값이라고 볼 수 있다.
2. 선형 회귀
- 비교적 간단하고 성능 뛰어남
- 특성이 하나인 경우, 어떤 직선을 학습
- y = a * x + b
- 기울기와 절편으로 구할 수 있음
📍 LinearRegression : sklearn.linear_model 패키지 아래에, 선형 회귀 알고리즘을 구현 가능
💻 선형 회귀 모델 훈련
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
# 선형 회귀 모델 훈련
lr.fit(train_input, train_target)
# 50cm 농어에 대해 예측
print(lr.predict([[50]]))
>>> [1241.83860323]
📍 coef_, intercept_ : LinearRegression 클래스가 찾은 a와 b
print(lr.coef_, lr.intercept_)
>>> [39.01714496] -709.0186449535477
🔎 식은 39.0174496x + (-709.0186449535477)
💻 농어의 길이 15~50 까지 직선 그리기 & 훈련 세트의 산점도
# 훈련 세트의 산점도
plt.scatter(train_input, train_target)
# 15에서 50까지 1차 방정식 그래프
plt.plot([15,50], [15*lr.coef_+lr.intercept_, 50*lr.coef_+lr.intercept_])
# 50cm 농어와 100cm 농어 데이터
plt.scatter(50, 1241.8, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
💻 훈련 세트와 테스트 세트에 대한 결정계수 점수 확인
print(lr.score(train_input, train_target))
print(lr.score(test_input, test_target))
>>> 0.939846333997604
>>> 0.8247503123313558
🔎 그래프 왼쪽 아래를 보면 길이가 15면 0보다 작은 무게..? 최적의 곡선이 필요하다!
3. 다항 회귀
💻 제곱한 값 만든 후 새롭게 만든 데이터셋 확인
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)
💻 train_poly 이용하여 선형 회귀 모델 다시 훈련
lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.predict([[50**2, 50]]))
>>> [1573.98423528]
💻 모델이 훈련한 계수와 절편 출력
print(lr.coef_, lr.intercept_)
>>> [ 1.01433211 -21.55792498] 116.0502107827827
🔎 이 모델은 무게 = 1.01 x 길이 x 길이 - 21.6 x 길이 + 116.05의 그래프를 학습했다.
📌 이런 방정식을 다항식이라고 부르며, 다항식을 사용한 선형 회귀를 다항 회귀라고 부른다.
💻 훈련 세트의 산점도에 그래프 그리기
# 구간별 직선을 그리기 위해 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.xlabel('length')
plt.ylabel('weight')
plt.show()
💻 훈련 세트와 테스트 세트의 결정계수 점수 확인
print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))
>>> 0.9706807451768623
>>> 0.9775935108325122
🔎 모든 길이에 해당하는 무게는 0보다 크다. 하지만 훈련 세트보다 테스트 세트가 여전히 높은 걸 보아, 과소적합이 남아있는 걸 알 수 있다.
3. 특성 공학과 규제
1. 다중 회귀
- 다중 회귀
: 여러 개의 특성을 사용한 선형 회귀 - 특성 공학
: 기존의 특성을 사용해 새로운 특성을 뽑아내는 작업
2. 데이터 준비
💻 판다스 임포트하여 데이터 프레임 만든 후, 넘파이 배열로 변환
import pandas as pd # 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])
💻 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)
3. 사이킷런의 변환기
📌 변환기
- 특성을 만들거나 전처리하기 위해, 사이킷런에서 제공하는 클래스.
- 타깃 데이터 없이 입력 데이터 변환
- fit한 후 transform 사용해야 함
📍 PolynomialFeatures
💻 2개의 특성 2와 3으로 이루어진 샘플 하나 적용
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures()
poly.fit([[2,3]])
print(poly.transform([[2, 3]]))
>>> [[1. 2. 3. 4. 6. 9.]]
📍 1의 경우, 절편에 해당한다. 사이킷런의 선형모델은 자동으로 절편을 추가하므로 불필요한 요소이다 .
따라서 include_bias=False로 지정하여 특성 변환
poly = PolynomialFeatures(include_bias=False)
poly.fit([[2,3]])
print(poly.transform([[2, 3]]))
💻 train_input에 적용하여 train_poly에 저장 후 배열의 크기 확인
poly = PolynomialFeatures(include_bias=False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
print(train_poly.shape)
>>> (42, 9)
📍 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)
💻 테스트 세트 변환
test_poly=poly.transform(test_input)
4. 다중 회귀 모델 훈련하기
💻 train_poly 사용해 모델 훈련 후 점수 확인
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
🔎 더 이상 과소적합 문제는 발생하지 않음!
💻 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개의 특성. train_poly 배열의 열의 개수가 특성의 개수
💻 선형 회귀 모델 훈련 후 점수 확인
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
>>> 0.9999999999996433
print(lr.score(test_poly, test_target))
>>> -144.40579436844948
🔎 테스트 세트에서 음수가 나왔다. 특성의 개수를 늘리면 선형 모델은 아주 강력해지는 것은 사실이다만, 훈련 세트에 너무 과대적합되므로 테스트 세트에서는 형편없는 점수를 만들어낸다.
5. 규제
📌 규제
- 머신러닝 모델이 훈련 세트에 과대적합되지 않도록 하는 것.
- 선형 모델의 경우, 특성에 곱해지는 계수(또는 기울기)의 크기를 작게 만듦
📍 StandardScaler : 정규화를 해주는 변환기
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_poly)
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)
🔎 StandardScaler 클래스의 객체 ss를 초기화한 후 PolynomialFeatures 클래스로 마든 train_polt를 사용하여 객체 훈련. 훈련 세트로 학습한 변환기를 사용하여 테스트 세트까지 변환해야 함
6. 릿지 회귀
📌 릿지 회귀
- 선형 회귀 모델에 규제를 추가한 모델
- 계수를 제곱한 값을 기준으로 규제
💻 릿지 모델 훈련 후 평가
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
>>> 0.9896101671037343
print(ridge.score(test_scaled, test_target))
>>> 0.9790693977615387
🔎 많은 특성을 사용했음에도 불구하고 훈련 세트에 너무 과대적합되지 않아 테스트 세트에서도 좋은 성능을 냄
📌 alpha
- 규제의 강도를 조절
- 값이 크면 규제 강도가 세짐 ➡ 계수 값을 더 줄여 과소적합되도록 유도
- 값이 작으면 계수를 줄이는 역할 줄어듦 ➡ 선형 회귀 모델과 유사해지면서 과대적합의 가능성 커짐
- 적잘한 alpha 값 찾는 법
- 결정계수의 값 그래프 그려보기
➡ 훈련 세트와 테스트 세트의 점수가 가장 가까운 지점이 최적의 alpha 값
- 결정계수의 값 그래프 그려보기
💻 맷플롯립을 임포트하고 alpha 값을 바꿀 때마다 score()메서드의 결과 저장할 리스트 생성
import matplotlib.pyplot as plt
train_score = []
test_score = []
💻 alpha 값을 0.001에서 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))
print(train_score)
print(test_score)
[0.9930455252088248, 0.991780998125052, 0.9903815817570367, 0.9896101671037343, 0.988728468997471, 0.9841843235774494]
[0.9569388961567329, 0.9800187936871725, 0.9827976465386928, 0.9790693977615387, 0.9725329582461569, 0.9627042641050291]
💻 alpha를 로그 함수로 바꾸어 지수로 표현한 그래프
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()
🔎 파란색이 훈련 세트 그래프, 주황색이 테스트 세트 그래프
왼쪽을 보면 훈련 세트와 테스트 세트의 점수 차이가 큼. 훈련 세트에는 잘 맞고, 테스트 세트에는 과대적합의 형태.
오른쪽은 훈련 세트와 테스트 세트의 점수가 모두 낮아지는 과소적합으로 가는 형태
➡ 적절한 alpha 값은 두 그래프가 가장 가깝고 테스트 세트의 점수가 가장 높은 -1, 즉 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.9903815817570367
>>> 0.9827976465386928
7. 라쏘 회귀
💻 라쏘 모델 훈련 후 평가
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
>>> 0.989789897208096
print(lasso.score(test_scaled, test_target))
>>> 0.9800593698421883
💻 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)
plt.plot(np.log10(alpha_list), test_score)
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.show()
🔎 왼쪽은 과대적합, 오른쪽으로 갈수록 훈련 세트와 테스트 세트의 점수가 좁혀지고 있음.
가장 오른쪽은 과소적합되는 모델.
라쏘 모델에서의 최적의 기준은 1, 즉 10
💻 모델 훈련
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
📌 라쏘 모델은 계수 값을 아예 0으로 만들 수 있다. 라쏘 모델의 계수는 coef 속성에 저장
print(np.sum(lasso.coef_==0))
>>> 40
🔎 55개의 특성을 모델에 주입했지만, 라쏘 모델이 사용한 특성은 15개밖에 되지 않음
➡ 이런 특징 때문에 라쏘 모델을 유용한 특성을 골라내는 용도로 사용 가능
'데이터 엔지니어링 과정 > python' 카테고리의 다른 글
[52일차] 다양한 분류 알고리즘 (0) | 2023.03.08 |
---|---|
[50일차] 나의 첫 머신러닝 & 데이터 다루기 (0) | 2023.03.06 |
[47일차] 데이터 분석하기 (0) | 2023.02.28 |
[15일차] 실전 데이터 분석 프로젝트 (0) | 2023.01.11 |
[14일차] 웹 API (0) | 2023.01.09 |