diff --git "a/week1/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" "b/week1/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" new file mode 100644 index 0000000..6052c16 --- /dev/null +++ "b/week1/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" @@ -0,0 +1,145 @@ +# KNN 알고리즘 개요 + +- 개념 : 어떤 데이터가 주어지면 그 주변의 데이터를 살펴본 뒤 더 많은 데이터가 포함되어 있는 범주로 분류하는 방식 +- 특징 : 훈련 데이터를 저장하는 것이 훈련의 전부이다. + +![](./images/2022-03-22-11-24-12.png) +
+
+
+# 혼공머신 - knn 알고리즘을 이용한 생선 분류 + +## **데이터 살펴보기** +

+![](./images/2022-03-22-11-34-17.png) + +왼쪽 영역에 분포하는 데이터가 빙어, 오른쪽 영역에 분포하는 데이터가 도미를 의미한다. + +앞으로 사용할 데이터를 다음과 같이 정의한다. +

+```python +length = bream_length + smelt_length +weight = bream_weight + smel_weight + +fish_data = [[l, w]] for l,w in zip(length, weight) + +# 1: 도미, 2: 빙어 +# 35 개의 도미 데이터와 14개의 빙어 데이터를 사용한다. +fish_target = [1]*35 + [0]*14 + +``` +

+## knn 알고리즘을 이용한 도미 빙어 데이터 구분 +

+사이킷 런의 KneighborsClassifer 를 통해 knn 알고리즘을 사용할 수 있다. +```python +from sklearn.neighbors import KNeighborsClassifier + +# KNN 객체 생성 +kn = KNeighborsClassifier(n_neighbors=49) +# fit() : 주어진 데이터로 알고리즘을 훈련 +kn.fit(fish_data, fish_target) +# score() : 0~1 사이의 값 반환 +kn.score(fish_data, fish_target) +``` +

+## **훈련 세트 & 데이터 세트 분리** +

+혼공머신 Chapter1,2 에서는 다음의 두 가지 방식으로 훈련 데이터와 테스트 데이터를 분류한다. + +- 각 데이터의 index를 랜덤으로 정렬해서 데이터를 임의로 뽑아내는 방식으로 훈련 데이터와 테스트 데이터를 분류한다. +- 사이킷런의 train_test_split 을 사용한다. + +두 번째 방식으로 데이터를 분리하는 것이 깔끔하다. + +```python +from sklearn.model_selection import train_test_split + +train_input, test_input, train_target, test_target = train_test_split(fish_data, fish_target, random_state = 42) +``` +

+## **데이터 학습** +

+데이터 전처리를 거치지 않고 일단, train data / test data 분리 된 것을 훈련시켰을 때 다음과 같은 결과가 나온다. + +*코드* +```python +kn = KNeighborsClassifier() +# train +kn.fit(train_input, train_target) +# test +kn.score(test_input, test_target) + +# (25, 150) 특성 값을 가지는 데이터를 예측해보자. +kn.predict([[25,150]]) >>> 결과값은 빙어(0) 를 가리킨다. + +# 최근접 이웃을 확인해보자. +# import matplotlib.pyplot as plt +plt.scatter(train_input[:, 0], train_input[:,1]) +plt.scatter(25, 150, marker='^') +# 최근접 이웃 표시 +plt.scatter(train_input[indexes,0], train_input[indexes,1], marker='D') +plt.show() +``` + +![](./images/2022-03-22-14-17-45.png) + +> 최근접 이웃 k = 5로 지정했을 때 과반수 이상의 3 개의 이웃이 빙어 데이터를 가리키므로 산접도 상 샘플 데이터는 도미에 가깝지만 빙어로 예측하게 된다. 이를 해결하기 위해 데이터 전처리 과정을 거쳐야 한다. + +

+ +## **데이터 전처리** +

+z-표준점수 정규화 방법을 사용한다. 즉, 다음의 수식을 활용한다. + +$$z = \frac{자료 값 - 평균}{표준편차}$$ + +*코드* +```python +# 평균, 표준편차 +# import nupmy as np +mean = np.mean(train_input, axis=0) +std = np.std(train_input, axis=0) + +# 전처리 데이터 +train_scaled = (train_input - mean) / std + +# 전처리 데이터로 모델 훈련 +plt.scatter(train_scaled[:,0], train_scaled[:,1]) +# 전처리 데이터와 마찬가지로 테스트 데이터도 전처리 해야됨. +plt.scatter(25, 150,marker='^') +plt.show() +``` +*결과* + +![](./images/2022-03-22-14-29-46.png) +> 빙어 데이터 와 샘플 데이터의 차이가 뚜렷해졌다. + +

+## **전처리 데이터로 모델 훈련** +

+*코드* +```python +new_sample_scaled = ([25, 150] - mean) / std +plt.scatter(train_scaled[:,0], train_scaled[:,1]) +plt.scatter(new_sample_scaled[0], new_sample_scaled[1]) + +# 최근접 이웃 표시 +distances, indexes = kn.kneighbors([new_sample_scaled]) +plt.scatter(train_scaled[:,0], train_scaled[:,1]) +plt.scatter(new_sample_scaled[0], new_sample_scaled[1], marker='^') +plt.scatter(train_scaled[indexes, 0], train_scaled[indexes, 1], marker='D') +plt.show() + +``` + +*결과* + +![](./images/2022-03-22-14-34-34.png) +

+최근접 이웃 모두 도미 데이터 이미로 샘플 데이터 역시 '도미' 로 예측하게 된다. +

+```python +print(kn.predict([new_sample_scaled])) +>>> [1] +``` diff --git a/week1/images/2022-03-22-11-24-12.png b/week1/images/2022-03-22-11-24-12.png new file mode 100644 index 0000000..2c257ae Binary files /dev/null and b/week1/images/2022-03-22-11-24-12.png differ diff --git a/week1/images/2022-03-22-11-33-30.png b/week1/images/2022-03-22-11-33-30.png new file mode 100644 index 0000000..398164a Binary files /dev/null and b/week1/images/2022-03-22-11-33-30.png differ diff --git a/week1/images/2022-03-22-11-33-47.png b/week1/images/2022-03-22-11-33-47.png new file mode 100644 index 0000000..398164a Binary files /dev/null and b/week1/images/2022-03-22-11-33-47.png differ diff --git a/week1/images/2022-03-22-11-34-17.png b/week1/images/2022-03-22-11-34-17.png new file mode 100644 index 0000000..e6adad8 Binary files /dev/null and b/week1/images/2022-03-22-11-34-17.png differ diff --git a/week1/images/2022-03-22-14-17-45.png b/week1/images/2022-03-22-14-17-45.png new file mode 100644 index 0000000..4c70f3f Binary files /dev/null and b/week1/images/2022-03-22-14-17-45.png differ diff --git a/week1/images/2022-03-22-14-24-50.png b/week1/images/2022-03-22-14-24-50.png new file mode 100644 index 0000000..0213407 Binary files /dev/null and b/week1/images/2022-03-22-14-24-50.png differ diff --git a/week1/images/2022-03-22-14-29-46.png b/week1/images/2022-03-22-14-29-46.png new file mode 100644 index 0000000..af19e7d Binary files /dev/null and b/week1/images/2022-03-22-14-29-46.png differ diff --git a/week1/images/2022-03-22-14-34-34.png b/week1/images/2022-03-22-14-34-34.png new file mode 100644 index 0000000..81ea0bb Binary files /dev/null and b/week1/images/2022-03-22-14-34-34.png differ diff --git "a/week2/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" "b/week2/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" new file mode 100644 index 0000000..4740dcd --- /dev/null +++ "b/week2/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" @@ -0,0 +1,328 @@ +# Notation + +## K-최근접 이웃 회귀 + +- k-최근접 이웃 회귀 알고리즘은 가장 가까운 n 개의 이웃을 선택, 확률을 계산하여 새로운 데이터 특성을 예측하는 방식이다. +- 계산 과정이 간단하지만 기존 데이터 범위를 넘어서는 경우 정확도가 매우 떨어진다. + +![](./images/2022-03-29-10-23-10.png) +
+

+## 선형 회귀 + +- 선형 회귀란 y = ax + b 와 같은 선형 방정식 형태로 표현. a 를 coefficient 라고 하고 b를 weight 라고 한다. +- 다항 회귀란, y를 x에 대한 다항식으로 표현하여 모델링하는 것을 말한다. n차 방정식과 동일. +
+

+## 다중 회귀 + +- 다중 회귀란 목표 변수 y를 여러 개의 독립된 변수 a,b,c ... 들의 관계로 나타내는 알고리즘이다. +- 다항 회귀는 독립변수 x의 차수가 n으로 높아진 것이며 다중 회귀는 이와 달리 서로 다른 독립 변수 a,b,c... 가 존재한다. + +![](./images/2022-03-29-10-27-49.png) +
+

+## Overfitting vs. Underfitting + +- overfitting : 어떤 모델이 훈련 데이터의 성질에 너무 깊게 학습되어 훈련 데이터에 대한 예측 성능은 매우 높지만 새로운 데이터에 대해서 score 가 매우 떨어지는 현상. + +- underfitting : 훈련 데이터의 특성이 충분히 학습되지 않아 성능이 떨어지는 현상. +-
+

+## 규제(릿지&라쏘) + +- 오버피팅을 막기 위해 모델이 과도하게 학습되는 것을 규제를 통해 조절. +- 계수를 제곱한 기준으로 규제를 가한 모델을 릿지, 절댓값을 기준으로 하면 라쏘 라고 한다. +

+![](./images/2022-03-29-10-32-28.png) +
+
+

+ +# 혼공머신 K-최근접 회귀 문제 + +목표 : 농어 길이 데이터를 바탕으로 무게를 추론하는 회귀 모델을 학습. +

+## 산점도로 데이터 살펴 보기 + +(미리 준비된 'perch_length', 'perch_weight' 데이터 이용.) + +![](./images/2022-03-29-10-39-43.png) +
+

+## train data & test data 분리 + +```python +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 +) + +# column vector 로 input 데이터 조정. +train_input = train_input.reshape(-1,1) +test_input = test_input.reshape(-1,1) +``` +

+## k-최근접 이웃 회귀 모델 훈련 + +```python +from sklearn.neighbors import KNeighborsRregressor +knr = KNeighborsRegressor() +knr.fit(train_input, train_target) # 모델 훈련 + +# 모델을 결정계수로 평가. +print(knr.score(test_input, test_target)) + +>>> 0.992809406101064 + +# 이웃의 개수를 3으로 설정해서 모델을 조금 더 예민하게 조정. +knr.fit(train_input, train_target) +print(knr.score(train_input, train_target)) +print(knr.score(test_input, test_target)) + +>>> 0.9804899950518966 +>>> 0.9746459963987609 +``` +

+## 선형 회귀 문제 + +- k-최근접 이웃 회귀 모델로 예측하기 어려운 새로운 데이터를 사용할 수 있도록 선형 회귀 모델 사용. +```python +# 기존 데이터에 없는 50cm 농어 데이터, 100cm 농어 데이터 +knr.predict([[50]]) + +>>> array([1033.33333333]) + +knr.predict([[100]]) + +>>> array([1033.33333333]) +``` +이웃 샘플이 동일 하기 때문에 같은 값으로 예측이 되는 문제 발생. 이런 문제를 선형 회귀를 통해 해결. +
+

+## 선형 회귀 모델 +```python +from sklearn.linear_model import LinearRegression +lr = LinearRegression() + +# 선형 회귀 모델을 훈련합니다. +lr.fit(train_input, train_target) + +# 15에서 50까지 1차 방정식 그래프를 그립니다. +plt.plot([15,50], [15*lr.coef_ + lr.intercept_, 50*lr.coef_ + lr.intercept_]) + +# 훈련 세트의 산점도를 그립니다. +plt.scatter(train_input, train_target) + +# 50cm 농어 데이터를 따로 표시합니다. +plt.scatter(50, lr.predict([[50]]), marker='^') +plt.xlabel('length') +plt.ylabel('weight') +plt.show() +``` +![](./images/2022-03-29-11-11-19.png) + +```python +# 훈련 점수와 테스트 점수 비교 +print(lr.score(train_input, train_target)) +print(lr.score(test_input, test_target)) + +>>> 0.939846333997604 +>>> 0.8247503123313558 +``` + +모델이 train data에 과도하게 학습되었음을 알 수 있다. overfitting 발생. + +```python +# 기존 데이터를 제곱한 값을 특성으로 추가. +train_poly = np.column_stack((train_input ** 2, train_input)) +test_poly = np.column_stack((test_input ** 2, test_input)) + +# 모델 훈련 +lr = LinearRegression() +lr.fit(train_poly, train_target) + +# train score, test score 재확인 +print(lr.score(train_poly, train_target)) +print(lr.score(test_poly, test_target)) + +>>> 0.9706807451768623 +>>> 0.9775935108325122 +``` +train score 와 test score 를 비교했을 때 이전 모델과는 다르게 overfitting 발생을 방지. +
+

+# 특성 공학과 규제 + +목표 +- 사이킷런의 다양한 도구를 활용하여 여러 특성을 사용한 다중 회귀 모델 구현 +- 복잡한 모델의 과대적합을 막기 위해 릿지와 라쏘 회귀 사용. +

+## 데이터 준비 + +앞서 사용했던 데이터에 특성이 하나 더 추가 된 'perch_full' 데이터 사용. +```python +import pandas as pd +df = pd.read_csv('https://bit.ly/perch_csv_data') +perch_full = df.to_numpy() # 판다스 -> 넘파이 배열 +``` + +```python +train_input, test_input, train_target, test_target = train_test_split( + perch_full, perch_weight, random_state=42) +``` +

+## PolynomialFeatures 클래스 + +PolynomialFeatures 클래스의 경우, 입력한 특성 관련해서 (특성)^2, (특성1)*(특성2) 같은 새로운 특성들을 계산하여 제공한다. + +train_input 데이터를 해당 클래스에 통과시키면 다음과 같은 결과를 보인다. + +```python +from sklearn.preprocessing import PolynomialFeatures +poly = PolynomialFeatures(include_bias=False) + +poly.fit(train_input) +train_poly = poly.transform(train_input) + +print(train_poly.shape) +print(poly.get_feature_names()) + +>>> (42, 9) # 9개의 특성. +>>> ['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2', 'x2^2'] +``` +위의 train_poly 데이터를 사용해 선형 회귀 모델을 훈련시켜 본다. + +```python +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 +``` +여전히 overfitting 현상이 남아 있다. + +특성의 개수를 추가시켜서 모델을 학습시켜 보자. + +```python +# PolynomialFeatures 클래스의 degree 파라미터를 변경하여 특성의 개수를 추가합니다. +poly = PolynomialFeatures(degree=5, include_bias=False) +poly.fit(train_input) +train_poly = poly.transform(train_input) +test_poly = poly.transform(test_input) + +# 모델 훈련 및 score 평가 +lr.fit(train_poly, train_target) +print(lr.score(train_poly, train_target)) +print(lr.score(test_poly, test_target)) + +>>> 0.9999999999938143 +>>> -144.40744532797535 +``` +오히려 훈련 세트에 대해 너무 과대적합되므로 테스트 데이터에 대한 점수가 굉장히 낮게 나온다. +
+

+## 규제 + +각 특성을 정규화한 후 규제를 적용해보자. +

+### 릿지 회귀 +```python +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)) + +>>> 0.9896101671037343 +>>> 0.979069397761539 +``` +score 사이 간의 차이가 줄어들었다. 최적의 규제깂을 확인해보자. +```python +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('log10(alpha)') #로그 스케일 +plt.ylabel('R^2') +plt.show() +``` +![](./images/2022-03-29-11-34-07.png) + +alpha = 0.1일 때 결정계수가 가장 큰 값을 보인다. + +```python +# alpha=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 +``` +

+### 라쏘 회귀 + +```python +# 각 계수의 절대값을 바탕으로 규제를 적용하는 라쏘 회귀를 사용합니다. +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)) + +>>> 0.989789897208096 +>>> 0.9800593698421884 +``` +alpha 조정을 통해 라쏘 회귀 역시 규제를 조절할 수 있다. 라쏘 회귀 역시 릿지 회귀에서와 동일한 과정을 거쳐 alpha 값에 따른 결정계수 그래프를 그려보면 다음과 같으며, 적절한 alpha 값을 찾을 수 있다. + +![](./images/2022-03-29-11-38-43.png) + +```python +# 그래프에서 보이는 최적의 alpha 값 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 +``` + +두 score 사이의 차이가 줄어들었다. overfitting을 어느 정도 조절하게 되었다. +

+## 라쏘 회귀의 또다른 기능 +```python +print(np.sum(lasso.coef_ == 0)) +>>> 40 +``` +라쏘 회귀는 절댓값을 사용하기 때문에 특정 계수를 0으로 만들 수 있다. 위의 코드 결과는 훈련과정에서 0이 된 파라미터의 개수가 40개 임을 확인할 수 있다. + +55개의 특성 중 40개가 0이고 나머지 15개 weights 만이 실질적으로 사용되며 이러한 특징은 라쏘 모델을 유용한 특성을 골라내는 용도로도 사용할 수 있음을 보여준다. \ No newline at end of file diff --git a/week2/images/2022-03-29-10-23-10.png b/week2/images/2022-03-29-10-23-10.png new file mode 100644 index 0000000..3e3bdc0 Binary files /dev/null and b/week2/images/2022-03-29-10-23-10.png differ diff --git a/week2/images/2022-03-29-10-27-49.png b/week2/images/2022-03-29-10-27-49.png new file mode 100644 index 0000000..d68aa59 Binary files /dev/null and b/week2/images/2022-03-29-10-27-49.png differ diff --git a/week2/images/2022-03-29-10-32-28.png b/week2/images/2022-03-29-10-32-28.png new file mode 100644 index 0000000..4c56dec Binary files /dev/null and b/week2/images/2022-03-29-10-32-28.png differ diff --git a/week2/images/2022-03-29-10-39-43.png b/week2/images/2022-03-29-10-39-43.png new file mode 100644 index 0000000..6b286e9 Binary files /dev/null and b/week2/images/2022-03-29-10-39-43.png differ diff --git a/week2/images/2022-03-29-11-11-19.png b/week2/images/2022-03-29-11-11-19.png new file mode 100644 index 0000000..cb7a64d Binary files /dev/null and b/week2/images/2022-03-29-11-11-19.png differ diff --git a/week2/images/2022-03-29-11-34-07.png b/week2/images/2022-03-29-11-34-07.png new file mode 100644 index 0000000..44a365a Binary files /dev/null and b/week2/images/2022-03-29-11-34-07.png differ diff --git a/week2/images/2022-03-29-11-38-43.png b/week2/images/2022-03-29-11-38-43.png new file mode 100644 index 0000000..d2f37f7 Binary files /dev/null and b/week2/images/2022-03-29-11-38-43.png differ diff --git "a/week3/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" "b/week3/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" new file mode 100644 index 0000000..bd9e5cb --- /dev/null +++ "b/week3/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" @@ -0,0 +1,212 @@ +# 이론 요약 +## 로지스틱 회귀 + +- 로지스틱 회귀는 선형 방정식을 통해 학습하는 분류 모델이다. +> ${z = a*( 특성1 ) + b*( 특성2 ) + ...}$ +- 시그모이드 함수를 통해 z 값을 0 과 1 사이로 만든다. +- ## 시그모이드 함수 : ${\Phi ={\frac {1}{1+e^-z}}}$ + + +## 로지스틱 회귀 다중 분류 + +- 로지스틱 회귀 함수는 이진 분류일 때 가장 강력한 성능을 발휘한다. +- 또한, 다중 분류일 때는 시그모이드 함수가 아닌 소프트맥스 함수를 사용한다. + + +## 소프트맥스 함수 : ${ y_i ={\frac {e^{z_i}}{\sum_{i=1}^K e^{z_i}}}}$ +- 소프트맥스 함수는 시그모이드 함수의 일반화 버전이다. +- k 개의 클래스에 대해 확률을 계산하여 분류할 수 있다. + + +## 손실함수, loss function +- 어떤 문제에서 머신러닝 알고리즘이 얼마나 부정확한지 측정하는 기준 +- 머신러닝은 손실 함수 결과가 최솟값이 나오도록 모델을 최적화하는 것이 목표가 된다. +- 로지스틱 손실함수는 '-log(예측확률)' 함수를 사용한다. + + +## 경사하강법 + +- Z = a*X0 + b*X1 + c*X2 + d 라고 할 때, 적절한 a,b,c,d 값을 찾기위한 최적화 알고리즘이다. +- 샘플 X = [ X0, X1, X2 ] 라고 하면 Z 는 a,b,c,d 에 대한 함수로 표현 가능하고 이 a,b,c,d 값으 바꿔가면서 경사가 최소값일 때를 찾는 알고리즘이다. + +#### 확률적 경사 하강법 (Stochastic gradient descent) +- 랜덤하게 하나의 샘플을 선택해 경사 하강법을 수행하는 방식 + +#### 미니 배치 경사 하강법 +- 여러 개의 샘플을 사용해 경사 하강법을 수행하는 방식 + +#### 배치 경사 하강법 +- 전체 샘플을 사용해 경사 하강법을 수행하는 방식 +

+ +# 혼공머신_예제 + +## K-최근접 이웃 분류기의 확률 예측 + +- ['Species'] 를 7개의 클래스로 설정(target_data) +- 특성 5개: 길이, 높이, 두께, 대각선, 무게 (train_data) +- train_test_split 으로 훈련 데이터, 테스트 데이터 분리 +- StandardScaler 클래스를 사용해 훈련 세트 및 테스트 세트 표준화 전처리 + +```python +import pandas as pd +fish = pd.read_csv('https://bit.ly/fish_csv_data') +# unqiue() 함수를 사용해서 어떤 종류의 생선이 있는지 확인 +print(pd.unique(fish['Species'])) + +>>> ['Bream' 'Roach' 'Whitefish' 'Parkki' 'Perch' 'Pike' 'Smelt'] + +# input data 설정 +fish_input = fish[['Weight', 'Length', 'Diagonal','Height','Width']].to_numpy() + +# target data 설정 +fish_target = fish['Species'].to_numpy() + +# 훈련 데이터, 테스트 데이터 분리 +from sklearn.model_selection import train_test_split +train_input, test_input, train_target, test_target = train_test_split( + fish_input, fish_target, random_state=42) + +# 표준화 전처리 +from sklearn.preprocessing import StandardScaler +ss = StandardScaler() +ss.fit(train_input) +train_scaled = ss.transform(train_input) +test_scaled = ss.transform(test_input) +``` + +```python +# 모델 생성 및 훈련 +from sklearn.neighbors import KNeighborsClassifier +kn = KNeighborsClassifier(n_neighbors=3) +kn.fit(train_scaled, train_target) +``` +

+## 로지스틱 회귀로 이진 분류 수행 + +- 데이터는 '도미'와 '빙어' 데이터를 사용. +- 시그모이드 함수의 출력 0.5보다 크면 양성 클래스, 0.5와 같거나 작으면 음성 클래스. + +```python +# 전체 데이터에서 boolean indexing 을 통해 도미와 빙어 데이터만 추출 +bream_smelt_indexes = (train_target == 'Bream') | (train_target == 'Smelt') +train_bream_smelt = train_scaled[bream_smelt_indexes] +target_bream_smelt = train_target[bream_smelt_indexes] + +# 로지스틱 회귀 모델 생성 및 훈련 +from sklearn.linear_model import LogisticRegression +lr = LogisticRegression() +lr.fit(train_bream_smelt, target_bream_smelt) +``` + +```python +# 처음 5개 샘플의 클래스를 분류 및 예측 확률 출력 +print(lr.predict(train_bream_smelt[:5])) + +>>> ['Bream' 'Smelt' 'Bream' 'Bream' 'Bream'] + +print(lr.predict_proba(train_bream_smelt[:5])) + +>>> [0.99759855 0.00240145] + [0.02735183 0.97264817] + [0.99486072 0.00513928] + [0.98584202 0.01415798] + [0.99767269 0.00232731] +``` +

+## 로지스틱 회귀로 다중 분류 수행하기 + +- 반복 횟수 (max_iter) = 1000 으로 설정 +- 계수의 제곱을 규제하는 L2 규제 적용 + +```python +# 다중 분류 모델 생성 및 훈련 +lr = LogisticRegression(C=20, max_iter=1000) +lr.fit(train_scaled, train_target) +``` + +```python +# 테스트 세트 처음 5개 샘플에 대한 분류, 예측 확률 출력 +print(lr.predict(test_scaled[:5])) + +>>> ['Perch' 'Smelt' 'Pike' 'Roach' 'Perch'] + +# 예측 확률 출력 +proba = lr.predict_proba(test_scaled[:5]) +print(np.round(proba, decimals=3)) + +>>> [0. 0.014 0.841 0. 0.136 0.007 0.003] + [0. 0.003 0.044 0. 0.007 0.946 0. ] + [0. 0. 0.034 0.935 0.015 0.016 0. ] + [0.011 0.034 0.306 0.007 0.567 0. 0.076] + [0. 0. 0.904 0.002 0.089 0.002 0.001] +``` + +```python +# 처음 샘플 5개에 대한 z 값을 소프트맥스 함수에 통과시키기 +decision = lr.decision_function(test_scaled[:5]) + +from scipy.special import softmax +proba = softmax(decision, axis=1) # 열 기준, 행에 대해 소프트맥스 계산. +print(np.round(proba, decimals=3)) + +>>> [0. 0.014 0.841 0. 0.136 0.007 0.003] + [0. 0.003 0.044 0. 0.007 0.946 0. ] + [0. 0. 0.034 0.935 0.015 0.016 0. ] + [0.011 0.034 0.306 0.007 0.567 0. 0.076] + [0. 0. 0.904 0.002 0.089 0.002 0.001] +``` +

+## SGDClassifier + +- 이진 분류의 경우, 이진 크로스엔트로피 손실 함수 +- 다중 분류의 경우, 크로스엔트로피 손실 함수 +- 경사 하강법 예제 데이터의 경우 앞선 7개 클래스에 대한 데이터를 그대로 사용한다. + +```python +# SGDClassifier 로드 +from sklearn.linear_model import SGDClassifier + +# 손실함수: loss='log' 로지스틱, 에포크: max_iter=10 +sc =SGDClassifier(loss='log', max_iter=10, random_state=42) +sc.fit(train_scaled, train_target) + +# score 출력 +print(sc.score(train_scaled, train_target)) +print(sc.score(test_scaled, test_target)) + +>>> 0.773109243697479 // score 가 다소 낮게 나오는 경향이 있다. + 0.775 +``` +

+## epoch와 과대/과소적합 + +- 확률적 경사 하강법을 사용한 모델은 epoch 횟수에 따라 과대/과소적합 현상이 나타난다. +- epoch 횟수가 적으면 과소적합이 발생하며, epoch 가 너무 많으면 과대적합이 발생한다. +- 과대적합이 시작되기 전 훈련을 멈추는 것을 'early stopping' 이라고 한다. +- 예제에서는 np.unique() 함수로 7개 생선 클래스 목록(=classes) 을 만든다. +- 과대적합이 발생하는 지점을 찾기 위해 epoch 1회 마다 train_score, test_score를 리스트로 logging 한다. +- partial_fit() 메서드를 통해 모델을 훈련한다. + +```python +# 모델 생성 및 훈련 준비 +import numpy as np +sc = SGDClassifier(loss='log', random_state=42) +train_score = [] +test_score = [] +classes = np.unique(train_target) + +# epochs= 300으로 설정하여 훈련 +for _ in range(0,300): + sc.partial_fit(train_scaled, train_target, classes=classes) + train_score.append(sc.score(train_scaled, train_target)) # train_score logging + test_score.append(sc.score(test_scaled, test_target)) # test_score logging + +# matplotlib 그래프로 확인 +import matplotlib.pyplot as plt +plt.plot(train_score) +plt.plot(test_score) +plt.xlabel('epoch') +plt.ylabel('accuracy') +plt.show() +``` \ No newline at end of file diff --git "a/week6/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" "b/week6/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" new file mode 100644 index 0000000..3ed49ce --- /dev/null +++ "b/week6/1\355\214\200_\354\230\244\353\217\231\355\233\210.md" @@ -0,0 +1,111 @@ +# 퍼셉트론(Perceptron) + +- 로지스틱 회귀 : 가중치와 편향을 이용하여 input에 대해 특정 확률을 계산. + +- McCulloch-Pitts Neuron : 로지스틱 회귀와 유사하게 선형 방정식을 통해 Yes / No 를 판별. + +- Perceptron : McCulloch-Pitts Neuron 과 유사하지만, input이 boolean이 아니어도 동작한다. 퍼셉트론의 약점은 XOR 문제를 해결하지 못한다는 점이며 이는 multi-layer perceptron 으로 해결할 수 있다. +

+ +# Multi-Layer Perceptron(MLP) + +- 퍼셉트론을 여러 개 쌓은 것 +- 입력층 + 은닉층 + 출력층 으로 구성되어 있다. + + + +## MLP (1) : 데이터로드 및 처리 + +```python +from tensorflow import keras +from sklearn.model_selection import train_test_split + +(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data() +train_scaled = train_input / 255.0 +train_scaled = train_scaled.reshape(-1, 28*28) + +train_scaled, val_scaled, train_target, val_target = train_test_split( + train_scaled, train_target, test_size=0.2, random_state=42) +``` + + +## MLP (2) : 모델 생성 + +```python +# 28*28 크기, grayscale image data 사용 + +model = keras.Sequential() +model.add(keras.layers.Flatten(input_shape=(28,28))) +model.add(keras.layers.Dense(100, activation='relu')) +model.add(keras.layers.Dense(10, activation='softmax')) +``` + + +## MLP (3.1) : 컴파일 및 훈련 + +```python +model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics='accuracy') +history = model.fit(train_scaled, train_target, epochs=20, verbose=0, + validation_data=(val_scaled, val_target)) +``` + + +## MLP (3.2) : callback 추가, 컴파일 및 훈련 + +```python +# 컴파일은 그대로 +model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', + metrics='accuracy') + +# ModelCheckpoint : 가장 낮은 검증 점수의 모델을 자동으로 저장 +checkpoint_cb = keras.callbacks.ModelCheckpoint('best-model.h5', + save_best_only=True) + +# EarlyStopping : patience 만큼 연속으로 검증 점수 향상되지 않으면 조기 종료. +early_stopping_cb = keras.callbacks.EarlyStopping(patience=2, + restore_best_weights=True) + +history = model.fit(train_scaled, train_target, epochs=20, verbose=0, + validation_data=(val_scaled, val_target), + callbacks=[checkpoint_cb, early_stopping_cb]) +``` + + +## MLP (4) : 모델의 저장과 복원 + +```python +# 모델 저장 +# 모델 파라미터만 저장. +model.save_weights('model-weights.h5') + +# 모델 구조와 모델 파라미터를 함께 저장. +model.save('model-whole.h5') + +# 모델 복원 +model_re = keras.models.load_model('model-whole.h5') +``` + +ModelCheckpoint 에서 이미 가장 좋은 성적을 내는 모델을 저장했기에 그대로 불러올 수 있다. + +```python +model_re_best = keras.models.load_model('best-model.h5') +``` + +# 최적화 문제 + +## 손실 함수(Loss Function) + +- 모델 성능이 얼마나 나쁜지 보여주는 함수이다. + +- 이진분류의 경우 binary_crossentropy, 회귀 모델의 경우 MSE 등을 사용한다. + +- DNN 에서는 손실값을 줄이는 방향으로 모델의 update가 진행되며 이를 최적화 라고 한다. + +## optimizer + +- 케라스는 다양한 경사 하강법 알고리즘을 제공하며 이들을 optimizer 라고 한다. + +- 모델 최적화를 위해 optimizer 종류를 선정하고 learning rate 를 조정하는 작업이 필요하다. + +- 기본 경사 하강법 optimizer : SGD / momentum +- 적응적 학습률 optimizer : RMSprop / Adam / Adagrad (모델이 최적점에 가까이 갈수록 학습률을 낮출 수 있다.) \ No newline at end of file