์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- ์ ํ
- ์ธํ๋ ์ด์
- CNN
- ์ธ๊ณต์ง๋ฅ
- AWS
- Python
- ์ฟผ๋ฆฌ๋ฌธ
- ์ฟผ๋ฆฌ
- ๋ฆฌํธ์ฝ๋
- oracle
- solvesql
- ์๋ง์กด
- ์ฝ๋ฉํ ์คํธ
- ๋ด์ค๋ ํฐ
- SQL
- ๋ ผ๋ฌธ์ฝ๊ธฐ
- ChatGPT
- leetcode
- ๋ฐ๋์ฒด
- spark
- NLP
- ๋ฅ๋ฌ๋
- API
- ํ๋ก๊ทธ๋๋จธ์ค
- ํ์ด์ฌ
- ์ฝํ
- ์ฝํ ์ค๋น
- Gan
- AI
- Paperreading
- Today
- Total
On the journey of
[ํธ์ฆ์จ๋จธ์ ๋ฌ๋] Chapter 3(3.1~3.7) ๋ณธ๋ฌธ
3.1 MNIST
๐ก MNIST ๋ฐ์ดํฐ์ (Modified National Institue of Standards and Technology Dataset) : ๊ณ ๋ฑํ์๊ณผ ๋ฏธ๊ตญ ์ธ๊ตฌ์กฐ์ฌ๊ตญ ์ง์๋ค์ด ์์ผ๋ก ์ด 70,000๊ฐ์ ์์ ์ซ์์ด๋ฏธ์ง๋ฅผ ๋ชจ์ ๋ฐ์ดํฐ์
- ๋จธ์ ๋ฌ๋ ๋ถ์ผ์ ‘Hello World’์ ๊ฐ์ ํ์ต์ฉ ๋ฐ์ดํฐ์
- MNIST ๋ฐ์ดํฐ์
๊ฐ์ ธ์ค๊ธฐ
- ‘mnist_784’ : id
- version=1 : ํ๋์ id์ ์ฌ๋ฌ ๊ฐ์ ๋ฒ์ ์ด ์์
- ์ถ๋ ฅ๊ฐ
- {'COL_NAMES':['label', 'data'], 'DESCR': ... 'data' : array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ... [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=uint8), 'target': array([0., 0., 0., ..., 9., 9., 9.]) }
- ๋์ ๋๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง.
- ‘DESCR’ : ๋ฐ์ดํฐ์ ์ค๋ช
- from sklearn.datasets import fetch_openml mnist = fetch_openml('mnist_784', version=1, as_frame=False)
- MNIST ๋ฐ์ดํฐ์ ์ ํฌ๊ธฐ๊ฐ ์ปค์ sklearn์ ๋ด์ฅ๋์ด์์ง ์๊ณ openml.org์ ๋จธ์ ๋ฌ๋ ๋ฐ์ดํฐ ๋ ํฌ์งํฐ๋ฆฌ์์ ๋ค์ด๋ก๋ํ๋ค. ์ด๋ฅผ ๋์์ฃผ๋ ๊ฒ์ด sklearn์ fetch_openml
- data์ target ๋ฐฐ์ด ์ดํด๋ณด๊ธฐ
X, y = mnist['data'], mnist['target']
X.shape # (70000, 784)
y.shape # (70000,)
- ์ด๋ฏธ์ง๊ฐ 70,000๊ฐ ์๊ณ ๊ฐ ์ด๋ฏธ์ง์๋ 784(28*28)๊ฐ์ ํน์ฑ์ด ์์.
- ๊ฐ ํน์ฑ์ 0(ํฐ์)๋ถํฐ 255(๊ฒ์์)๊น์ง์ ํฝ์ ๊ฐ๋
- MNIST ๋ฐ์ดํฐ ํ๋ ์ดํด๋ณด๊ธฐ
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
some_digit = X[0] # as_frame=False ์๋๋ฉด KeyError
some_digit_image = some_digit.reshape(28, 28) # ์ฌ๋ฐฐ์ด
plt.imshow(some_digit_image, cmap=matplotlib.cm.binary, interpolation="nearest")
plt.axis("off")
plt.show()
- y[0] ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ ‘5’๋ก ๋ง๋ ๋ ์ด๋ธ์ด ๋์ด์์์ ์ ์ ์๋ค.
- ํ
์คํธ ์ธํธ์ ์ค์
- ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๊ธฐ ์ ์ ํญ์ ํ ์คํธ ์ธํธ๋ฅผ ๊ตฌ๋ถํด๋์์ผ ํจ
- MNIST ๋ฐ์ดํฐ์ ์ ์ด๋ฏธ ํ๋ จ ์ธํธ(์์ชฝ 60,000๊ฐ ์ด๋ฏธ์ง)์ ํ ์คํธ ์ธํธ(๋ค์ชฝ 10,000๊ฐ ์ด๋ฏธ์ง)๋ก ๋๋จ
- ์ด๋ฏธ์ง๊ฐ ๋๋คํ๊ฒ ์์ฌ์๊ธฐ๋๋ฌธ์ ์์๋๋ก ๋๋ ๋ ๋ฌด๋ฐฉ
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
- ์์๋๋ก ๋๋ ๊ฒ์ด ๊ฑฑ์ ๋๋ค๋ฉด?
- ํ๋์ ํด๋์ ํน์ ์ซ์๊ฐ ๋๋ฝ๋ ๊ฒฝ์ฐ,
- ๋น์ทํ ์ํ์ด ์ฐ์ด์ด ๋ํ๋๋ ๊ฒฝ์ฐ,
- ํ์ต ์๊ณ ๋ฆฌ์ฆ์ ์ฑ๋ฅ์ด ๋๋น ์ง
import numpy as np shuffle_index = np.random.permutation(60000) X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]
3.2 ์ด์ง๋ถ๋ฅ๊ธฐ ํ๋ จ
<aside> ๐ก ์ด์ง๋ถ๋ฅ๊ธฐ (Binary Classifier) : ๋ฐ์ดํฐ๋ฅผ ์์ฑ ํด๋์ค์ ์์ฑ ํด๋์ค ๋ ๊ฐ์ง๋ก ๋ถ๋ฅ : ๊ธฐ๋ณธ์ MNIST ๋ฐ์ดํฐ์ ์ 0~9์ ์๋ก ๋ถ๋ฅํ๋ ๊ฒ์ ๋ค์ค๋ถ๋ฅ์ ์
</aside>
- ๊ธฐ์กด MNIST ๋ฐ์ดํฐ์ ๋ถ๋ฅ ๋ฌธ์ ๋ฅผ ๋จ์ํํ์ฌ ‘5’์ ‘5๊ฐ ์๋ ์’๋ฅผ ๋ถ๋ฅํ๋ ์ด์ง๋ถ๋ฅ๊ธฐ๋ฅผ ๋ง๋ค์ด๋ณด๊ณ ์ ํจ.
- ๋ถ๋ฅ ์์ ์ ์ํด ํ๊น ๋ฒกํฐ๋ฅผ ๋ง๋ฆ
y_train_5 = (y_train == 5) # 5๋ผ๋ฉด True๋ก, 5๊ฐ ์๋ ๋ค๋ฅธ ์๋ผ๋ฉด False๋ก ์ ์ฅ
y_test_5 = (y_test == 5)
- ๋ถ๋ฅ ๋ชจ๋ธ ์ค ํ๋์ธ ํ๋ฅ ์ ๊ฒฝ์ฌํ๊ฐ๋ฒ(Stochastic Gradient Descent, SGD) ๋ถ๋ฅ๊ธฐ ์ด์ฉ. (์์ธํ ๋ด์ฉ์ ๋ค์์ฅ์ ๋์ค๋ฏ๋ก ์ธ๋ถ ์ค๋ช ์๋ต)
- sklearn์ SGDClassifier ํด๋์ค ์ด์ฉ
from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier(max_iter=5, random_state=42)
sgd_clf.fit(X_train, y_train_5)
- ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์ซ์ 5์ ์ด๋ฏธ์ง ๊ฐ์ง
sgd_clf.predict([some_digit]) # array([True], dtype=bool), ํน๋ณํ๊ฒ ๋ง์ถ ์ผ์ด์ค
3.3 ์ฑ๋ฅ ํ๊ฐ
- ๋ถ๋ฅ๊ธฐ ํ๊ฐ๋ฅผ ์ํ ์ฌ๋ฌ ์ฑ๋ฅ ์งํ ๋น๊ต
3.3.1 ๊ต์ฐจ ๊ฒ์ฆ์ ์ฌ์ฉํ ์ ํ๋ ์ธก์
<aside> ๐ก K-๊ฒน ๊ต์ฐจ ๊ฒ์ฆ (K-Fold Cross Validation) : ํ๋ จ์ธํธ๋ฅผ K๊ฐ์ ํด๋๋ก ๋๋๊ณ , ๊ฐ ํด๋์ ๋ํด ์์ธก์ ๋ง๋ค๊ณ ํ๊ฐํ๊ธฐ ์ํด ๋๋จธ์ง ํด๋๋ก ํ๋ จ์ํจ ๋ชจ๋ธ์ ์ฌ์ฉ
</aside>
- cross_val_score() ํจ์ ์ด์ฉ : ์ ํ๋(accuracy)
from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy") # K = 3
# array([0.9502, 0.96565, 0.96495])
- ๋ชจ๋ ์ ํ๋๊ฐ 95% ์ด์ → “์ข์ ๊ฒฐ๊ณผ์ธ๊ฐ?”
- ์์
- ๋จ์ ๊ณ์ฐ์ผ๋ก ์ ์ฒด MNIST ๋ฐ์ดํฐ์
์ ์ซ์ 5์ ์ด๋ฏธ์ง๋ ์ฝ 10% ์ ๋๋ผ๊ณ ๊ฐ์ ํ๋ฉด ๋ฌด์กฐ๊ฑด 5๊ฐ ์๋๋ผ๊ณ ์์ธกํ๋ค๋ฉด 90% ๋ด์ธ์ ์ ํ๋๋ฅผ ์ป์ ์ ์์
- ์ ํ๋๋ ํนํ ๋ถ๊ท ํํ ๋ฐ์ดํฐ์ ์ ๋ค๋ฃฐ ๋ ๋ถ๋ฅ๊ธฐ์ ์ฑ๋ฅ ์ธก์ ์งํ๋ก ์ ํธ๋์ง ์๋๋ค.
- from sklearn.base import BaseEstimator class Never5Classifier(BaseEstimator): def fit(self, X, y=None): pass def predict(self, X): return np.zeros((len(X), 1), dtype=bool) never_5_clf = Never5Classifier() cross_val_score(never_5_clf, X_train, y_train_5, cv=3, scoring='accuracy') # array([0.909, 0.90715, 0.9128])
3.3.2 ์ค์ฐจ ํ๋ ฌ
๐ก ์ค์ฐจ ํ๋ ฌ (confusion matrix) : ์ค์ ๋ก ์ฐธ์ธ์ง ๊ฑฐ์ง์ธ์ง, ์์ธก์ ๊ธ์ ์ผ๋ก ํ๋์ง, ๋ถ์ ์ผ๋ก ํ๋์ง์ ๋ฐ๋ผ ๋ค ๊ฐ์ ๊ฒฝ์ฐ์ ์๋ก ๊ตฌ๋ถํ ํ
- ์ค์ฐจ ํ๋ ฌ ๋ง๋ค๊ธฐ
- ์ฐ์ ์ค์ ํ๊น๊ณผ ๋น๊ตํ ์ ์๋๋ก ์์ธก๊ฐ์ ๋ง๋ค์ด์ผ ํจ → cross_val_predict() ํจ์ ์ด์ฉ : ๊ฐ ํ ์คํธ ํด๋์์ ์ป์ ์์ธก ๋ฐํ
from sklearn.model_selection import cross_val_predict y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)
- confusion_matrix() ํจ์ ์ด์ฉํ์ฌ ์ค์ฐจ ํ๋ ฌ ๋ง๋ฆ.
์์ธก ์์ฑ ์์ธก ์์ฑfrom sklearn.metrics import confusion_matrix confusion_matrix(y_train_5, y_train_pred) # array([[53272, 1307], # [1077, 4344]])
์ค์ ์์ฑ ์ง์ง์์ฑ (TN) ๊ฐ์ง์์ฑ (FP) ์ค์ ์์ฑ ๊ฐ์ง์์ฑ (FN) ์ง์ง์์ฑ (TP) - ์๋ฒฝํ ๋ถ๋ฅ๊ธฐ๋ผ๋ฉด FP = FN = 0
๐ก ์ ๋ฐ๋ (precision) : ์์ฑ ์์ธก์ ์ ํ๋ : ์์ฑํด๋์ค๋ก ์์ธกํ ๊ฒ ์ค ์ง์ง์์ฑ์ ๋น์จ
์ ๋ฐ๋ = {TP}/{TP+FP}
๐ก ์ฌํ์จ (recall) = ๋ฏผ๊ฐ๋ (sensitivity) = ์ง์ง์์ฑ๋น์จ (true positive rate; TPR) : ๋ถ๋ฅ๊ธฐ๊ฐ ์ ํํ๊ฒ ๊ฐ์งํ ์์ฑ ์ํ์ ๋น์จ : “์ค์ ์์ฑ ์ค ์ง์ง์์ฑ์ผ๋ก ์ผ๋ง๋ ๋ถ๋ฅ๋์๋๊ฐ”
์ฌํ์จ ={TP}/{TP+FN}
- ex)
3.3.3 ์ ๋ฐ๋์ ์ฌํ์จ
- ํ์ด์ฌ์์๋ ์ ๋ฐ๋์ ์ฌํ์จ์ ๊ณ์ฐํ๋ ํจ์๋ฅผ ์ ๊ณต
from sklearn.metrics import precision_score, recall_score
precision_score(y_train_5, y_train_pred) # == 4344 / (4344 + 1307)
# 0.768713...
recall_score(y_train_5, y_train_pred) # == 4344 / (4344 + 1077)
# 0.801328...
- 3.2.1์ ์ ํ๋์ ๋นํด, 5๋ก ํ๋ณ๋ ์ด๋ฏธ์ง ์ค 77%๋ง ์ ํํ๊ณ ์ ์ฒด ์ซ์ 5์์ 80%๋ง ๊ฐ์งํ ์ฌ์ค์ ์ฑ๋ฅ์ด ์ข์๋ณด์ด์ง ์์
๐ก F1์ ์ (F1 score) : ์ ๋ฐ๋์ ์ฌํ์จ์ ์กฐํ ํ๊ท (harmonic mean) : ๋ ๋ถ๋ฅ๊ธฐ๋ฅผ ๋น๊ตํ ๋ ํธ๋ฆฌ
- F1 ์ ์ ๊ณ์ฐ ์ f1_score() ํจ์ ์ด์ฉ
from sklearn.metrics import fl_score
fl_score(y_train_5, y_train_pred)
# 0.78468...
- ์ ๋ฐ๋์ ์ฌํ์จ์ ๋ฐ๋น๋ก ๊ด๊ณ๋ฅผ ์ ๋ฐ๋/์ฌํ์จ ํธ๋ ์ด๋์คํ๋ผ๊ณ ํจ.
3.3.4 ์ ๋ฐ๋/์ฌํ์จ ํธ๋ ์ด๋ ์คํ
SGDClassifier์ ๋ถ๋ฅ๋ฅผ ํตํด ํธ๋ ์ด๋ ์คํ ์ดํด
์ด ๋ถ๋ฅ๊ธฐ๋ ๊ฒฐ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ํ์ ์ ์๋ฅผ ๊ณ์ฐ
- ์ํ์ ์>์๊ณ๊ฐ→์์ฑํด๋์ค
- ์ํ์ ์<์๊ณ๊ฐ→์์ฑํด๋์ค
5์ ๋ํ train data๋ฅผ ์ฌ์ฉํ ๋, ์ค์ ์์ฑ (# of (tp+fn)) = 6์ด๋ฏ๋ก ๋งจ ์ค๋ฅธ์ชฝ ์๊ณ๊ฐ์ ๋ํด
์ ๋ฐ๋ = ์ง์ง ์์ฑ(# of ๋ถ๋ฅ๊ธฐ ์ค์ 5์ ์ = 3 ) / ์์ฑ์ผ๋ก ์์ธก( # of ๋ถ๋ฅ๊ธฐ ๊ฐ์ง = 3) = 100%
์ฌํ์จ = ์ง์ง ์์ฑ(# of ๋ถ๋ฅ๊ธฐ ์ค์ 5์ ์ = 3 ) / ์ค์ ์์ฑ( # of ์ค์ 5์ธ ๊ฐ = 6) = 50%
์๊ณ๊ฐ์ด ๋์์ง ์๋ก ์ ๋ฐ๋ ↑ ์ฌํ์จ ↓
์๊ณ๊ฐ์ด ๋ฎ์์ง ์๋ก ์ ๋ฐ๋ ↓ ์ฌํ์จ ↑
SGDClassifier์ ํน์ ํด๋์ค(0~9์ค 1๊ฐ)์ ๋ํ ์์ธก๊ฐ
y_scores = sgd_clf.decision_function([some_digit])
y_scores
>>array([303905.39584261])
# ์๊ณ์ = 0์ ๋ํ ์์ธก๊ฐ
threshold = 0
y_some_digit_pred = (y_scores>threshold)
y_some_digit_pred
>>array([ True]) #3๋ฅผ ์ ์์ธกํ ๊ฒ์ ์ ์ ์์
์๊ณ๊ฐ ์ฆ๊ฐํ๋ฉด ์ฌํ์จ์ด ์ค์ด๋ฆ
์ฆ, ์๊ณ๊ฐ์ด 0์ผ๋, ๋ถ๋ฅ๊ธฐ๊ฐ ์ซ์ 3๋ฅผ ๊ฐ์งํ์ผ๋ ์๊ณ๊ฐ์ด 100000000๋ก ๋์ด๋ฉด ์ด๋ฅผ ๋์น๊ฒ ๋จ
# ์๊ณ์ : 0 → 100000000
threshold = 100000000
y_some_digit_pred = (y_scores > threshold)
y_some_digit_pred
>>array([False]) # ์๊ณ์ ์ ๋์ด๋ 3๋ฅผ ์์ธกํ์ง ๋ชปํจ
# ์๊ณ์ ๊ณ์ฐ
y_scores = cross_val_predict(sgd_clf, X_train, y_train_3, cv = 3,
method = 'decision_function')
precision_recall_curve(): ๋ชจ๋ ์๊ณ๊ฐ์ ๋ํ ์ ๋ฐ๋์ ์ฌํ์จ ๊ณ์ฐ
from sklearn.metrics import precision_recall_curve
precisions, recalls, thresholds = precision_recall_curve(y_train_3, y_scores)
์๊ณ๊ฐ์ ๋ํ ์ ๋ฐ๋/์ฌํ์จ ํจ์
์ ๋ฐ๋์ ์ฌํ์จ์ ํธ๋ ์ด๋์คํ ๊ด๊ณ๋ฅผ ์ ์ ์์
์ ๋ฐ๋๋ ๋์ด๋, ์ฌํ์จ์ ์ด๋์ ๋ ํ๋ณดํ ์ ์๋ ์ ์ ํ ์๊ณ์ ์ ์ฐพ๋ ๊ฒ์ด ์ค์
# ์ ๋ฐ๋ 90 ๋ชฉํ๋ก ์ธํ
y_train_pred_90 = (y_scores > 70000)
print(precision_score(y_train_3, y_train_pred_90)) #์ ๋ฐ๋
>>0.8810385188337945
print(recall_score(y_train_3, y_train_pred_90)) #์ฌํ์จ
>>0.675256891208612
3.5 ROC ๊ณก์
๐ก reciver operating characteristic : ๊ฑฐ์ง์์ฑ๋น์จ(FPR)์ ๋ํ ์ง์ง ์์ฑ๋น์จ(TPR, ์ฌํ์จ)
- FPR = ๊ฑฐ์ง์์ฑ/์ค์ ์์ฑ
- TNR(ํน์ด๋) = ์ง์ง์์ฑ/์ค์ ์์ฑ
ROC ๊ณก์ ์ ๋ฏผ๊ฐ๋(์ฌํ์จ,TPR)์ ๋ํ 1- ํน์ด๋(TNR)
from sklearn.metrics import roc_curve
# roc_curve๋ฅผ ์ด์ฉํด ์ฌ๋ฌ ์๊ณ๊ฐ์์ TPR๊ณผ FPR ๊ณ์ฐ
fpr, tpr, thresholds = roc_curve(y_train_3, y_scores)
์๋ ๊ทธ๋ํ๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ,
์ฌํ์จ ⇑ → ๋ถ๋ฅ๊ธฐ๊ฐ ๋ง๋๋ ๊ฑฐ์ง ์์ฑ ⇑
๊ณก์ ์๋์ ๋ฉด์ (area under the curve:AUC) ์๋ฒฝํ ๋ถ๋ฅ๊ธฐ๋ ROC์ AUC๊ฐ 1์ด๊ณ , ์์ ํ ๋๋ค ๋ถ๋ฅ๊ธฐ๋ 0.5
๋ฌด์์๋ก ์์ธกํ ๊ฒฝ์ฐ ์ค์ฐจ ํ๋ ฌ์ ์ค์ ํด๋์ค๊ฐ ๋น์ทํ ๋น์จ์ ์์ธก ํด๋์ค๋ก ๋๋์ด FPR๊ณผ TPR์ ๊ฐ์ด ๋น์ทํด์ง.
๊ฒฐ๊ตญ ROC ๊ณก์ ์ด y=x์ ๊ฐ๊น๊ฒ ๋์ด AUC ๋ฉด์ ์ด 0.5๊ฐ ๋จ.
SGDClassifier vs ๋๋คํฌ๋ ์คํธ Classifier
#RandomForestClassifier
# decision_function()์ด ์์ผ๋ฏ๋ก predict_proba()์ด์ฉ
from sklearn.ensemble import RandomForestClassifier
forest_clf = RandomForestClassifier(n_estimators=10, random_state=42)
y_probas_forest = cross_val_predict(forest_clf, X_train, y_train_3, cv=3,
method="predict_proba")
#ROC ๊ณก์ ์ ๊ทธ๋ฆฌ๋ ค๋ฉด ํ๋ฅ ์ด ์๋ ์ ์ ํ์
# ์์ฑํด๋์ค์ ํ๋ฅ ์ ์ ์๋ก ํ์ฉ
y_scores_forest = y_probas_forest[:, 1] #set ์์ฑํด๋์ค ํ๋ฅ = ์ ์
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_3,y_scores_forest)
# randomforestcalssfier >> SGDClassfier roc ๊ทธ๋ํ ๊ทธ๋ฆผ
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, "b:", linewidth=2, label="SGD")
plot_roc_curve(fpr_forest, tpr_forest, "๋๋ค ํฌ๋ ์คํธ")
plt.legend(loc="lower right", fontsize=16)
plt.show()
# ๋๋คํฌ๋ ์คํธ ๋ถ๋ฅ๊ธฐ์ score
from sklearn.metrics import roc_auc_score
roc_auc_score(y_train_3, y_scores_forest) # SGD๊ฐ๋ณด๋ค ํฅ์ ํผ
>>0.9863627257748906
3.4 ๋ค์ค ๋ถ๋ฅ
* ๋ค์ค ๋ถ๋ฅ๊ธฐ(๋คํญ ๋ถ๋ฅ๊ธฐ): ๋ ์ด์์ ํด๋์ค๋ฅผ ๊ตฌ๋ณ
- ์ด์ง ๋ถ๋ฅ๊ธฐ๋ฅผ ์ฌ๋ฌ๊ฐ ์ฌ์ฉํด ๋ค์ค ํด๋์ค ๋ถ๋ฅ ์) 0~9๊น์ง ํ๋ จ์์ผ ํด๋์ค๊ฐ 10๊ฐ์ธ ์ซ์ ์ด๋ฏธ์ง ๋ถ๋ฅ
- OvA(์ผ๋๋ค ์ ๋ต): ์์คํ ์์ ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฅํ ๋ ๊ฐ ๋ถ๋ฅ๊ธฐ์ ๊ฒฐ์ ์ ์ ์ค์์ ๊ฐ์ฅ ๋์ ๊ฒ์ ํด๋์ค๋ก ์ ํ
- OvO(์ผ๋์ผ ์ ๋ต): ํ ๋๋จผํธ์์ผ๋ก 0๊ณผ 1 ๊ตฌ๋ณ, 0๊ณผ 2 ๊ตฌ๋ณ, 1๊ณผ 2 ๊ตฌ๋ณ ๋ฑ๊ณผ ๊ฐ์ด ๊ฐ ์ซ์์ ์กฐํฉ๋ง๋ค ์ด์ง ๋ถ๋ฅ๊ธฐ๋ฅผ ํ๋ จ
- OvO ๊ณ์ฐ์: ํด๋์ค N๊ฐ → ๋ถ๋ฅ๊ธฐ
- ์ฅ์ : ๊ฐ ๋ถ๋ฅ๊ธฐ์ ํ๋ จ์ ์ ์ฒด ํ๋ จ ์ธํธ ์ค ๊ตฌ๋ณํ ๋ ํด๋์ค์ ํด๋นํ๋ ์ํ๋ง ํ์!!
๋๋ถ๋ถ ์ด์ง๋ถ๋ฅ: OvA์ ํธ
๋จ ์ํฌํธ๋ฒกํฐ ๋จธ์ ๊ฐ์ ์ผ๋ถ ์๊ณ ๋ฆฌ์ฆ(=ํ๋ จ ์ธํธ์ ํฌ๊ธฐ์ ๋ฏผ๊ฐ)์ OvO์ ํธ
SGD ๋ค์ค ๋ถ๋ฅ
๋ค์ค ๋ถ๋ฅ ๋ฐฉ์: y_train์ด์ฉํด ์ฌ๋ฌ ํด๋์ค ๋ถ๋ฅ ์์
- 3์ ๊ตฌ๋ณํ ํ๊น ํด๋์ค(y_train_3) ๋์ 0~9๊น์ง์ ์๋ ํ๊น ํด๋์ค(y_train)์ ์ฌ์ฉํด SGDClassifier์ ์๋ จ
- ๊ทธ๋ฐ๋ค์ ์์ธก์ ํ๋ํจ-> ๊ฒฐ๊ณผ: ์ ํํ ๋ง์ถค
- ์ฌ์ดํท๋ฐ์ด ์ค์ ๋ก 10๊ฐ์ ์ด์ง ๋ถ๋ฅ๊ธฐ๋ฅผ ํ๋ จ์ํค๊ณ ๊ฐ๊ฐ์ ๊ฒฐ์ ์ ์๋ฅผ ์ป์ด ์ ์๊ฐ ๊ฐ์ฅ ๋์ ํด๋์ค๋ฅผ ์ ํ
sgd_clf.fit(X_train,y_train) # y_train_3์ด ์๋ y_train ์ฌ์ฉ
sgd_clf.predict([some_digit])
>>array([3])
๋ค์ค ๋ถ๋ฅ ๋ฐฉ์: decision_function() ์ด์ฉ
- decision_function(): ์ฌ์ดํท๋ฐ์ด ์ค์ ๋ก 10๊ฐ์ ์ด์ง ๋ถ๋ฅ๊ธฐ๋ฅผ ํ๋ จ์ํค๊ณ ๊ฐ๊ฐ์ ๊ฒฐ์ ์ ์๋ฅผ ์ป์ด ์ ์๊ฐ ๊ฐ์ฅ ๋์ ํด๋์ค๋ฅผ ์ ํ๊ฐ ๋ง๋์ง ํ์ธ
- ์ํ ํ๋์ ์ ์๊ฐ ์๋๋ผ ํด๋์ค๋ง๋ค ํ๋์ฉ, ์ด 10๊ฐ์ ์ ์๋ฅผ ๋ฐํ
some_digit_scores = sgd_clf.decision_function([some_digit])
some_digit_scores # ๊ฐ์ฅ ๋์ ๊ฐ: 129738.57895132 -> index = 3์.
>>array([[-620766.3293308 , -303658.02060956, -420512.63999577,
129738.57895132, -612558.43668255, -181995.32698842,
-573231.01600869, -264848.38137796, -192137.27888861,
-272236.34656753]])
๊ทธ๋ฆฌ๊ณ SGD ๋ถ๋ฅ๊ธฐ์ ๋ํ ์ถ์ ์น & ์ค์ ๊ฐ
print('์ถ์ ๊ฐ:{}'.format(np.argmax(some_digit_scores))) # index๊ฐ 3์ด ๋ง๋์ง ์ฒดํฌ
>>์ถ์ ๊ฐ:3
print('sgd๊ฐ ๋ถ๋ฅํ mnist๊ฐ:{}'.format(sgd_clf.classes_))
>>sgd๊ฐ ๋ถ๋ฅํ mnist๊ฐ:[0 1 2 3 4 5 6 7 8 9]
print('sgd๊ฐ ๋ถ๋ฅํ minist ์ธ๋ฑ์ค์ ์ค์ ๊ฐ:{}'.format(sgd_clf.classes_[3]))
>>sgd๊ฐ ๋ถ๋ฅํ minist ์ธ๋ฑ์ค์ ์ค์ ๊ฐ:3
OvO๋ OvA ๊ฐ์ ์ฌ์ฉ ๋ฐฉ๋ฒ
# OvO๋ OvA ๊ฐ์ ์ฌ์ฉ
from sklearn.multiclass import OneVsOneClassifier
ovo_clf = OneVsOneClassifier(SGDClassifier(max_iter=5, random_state=42))
ovo_clf.fit(X_train, y_train)
ovo_clf.predict([some_digit])
print(ovo_clf.fit(X_train, y_train))
>>OneVsOneClassifier(estimator=SGDClassifier(max_iter=5, random_state=42))
print(ovo_clf.predict([some_digit]))
>>[3]
print(len(ovo_clf.estimators_))
>>45
๋๋คํฌ๋ ์คํธ ๋ค์ค ๋ถ๋ฅ
print(forest_clf.fit(X_train, y_train))
>>RandomForestClassifier(n_estimators=10, random_state=42)
print(forest_clf.predict([some_digit]))
>>[3]
๋๋คํฌ๋ ์คํธ๋ถ๋ฅ๊ธฐ์ ๊ฒฝ์ฐ ์ง์ ํด๋์ค๋ฅผ ๋ถ๋ฅํ๊ณ predict_proba()๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ๊ฐ ๋ถ๋ฅ์ ํ๋ฅ ์ด ๊ณ์ฐ๋จ
forest_clf.predict_proba([some_digit])
>>array([[0. , 0. , 0. , 0.9, 0. , 0. , 0. , 0. , 0. , 0.1]])
๋ถ๋ฅ๊ธฐ ์ฑ๋ฅ code
cross_val_score(sgd_clf, X_train, y_train, cv= 3, scoring = 'accuracy')
>>array([0.8639 , 0.82125, 0.8595 ])
์ฑ๋ฅ ํฅ์: ์ ๋ ฅ ์ค์ผ์ผ์ ํ์คํํด ์ ํ๋๋ฅผ ๋์.
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train.astype(np.float64))
cross_val_score(sgd_clf, X_train_scaled, y_train, cv = 3, scoring = 'accuracy')
>>array([0.90985, 0.9104 , 0.9097 ])
3.5 ์๋ฌ ๋ถ์
1. ์ค์ฐจ ํ๋ ฌ ๋ถ์ : ๋ถ๋ฅ๊ธฐ์ ์ฑ๋ฅ ํฅ์ ๋ฐฉ์์ ๋ํ ํต์ฐฐ์ ์ป์ ์ ์๋ค.
- ์ผ๋จ ์ค์ฐจ ํ๋ ฌ ๋ง๋ค์ด๋ณด๊ธฐ:
y_train_pred = cross_val_predict(sgd_clf, X_train_scaled, y_train, cv=3)
conf_mx = confusion_matrix(y_train, y_train_pred)
conf_mx
์ด๋ ์ค์ฐจ ํ๋ ฌ์ ์ด๋ฏธ์ง๋ก ๋ณด๊ณ ์ถ๋ค๋ฉด:
plt.matshow(conf_mx, cmap=plt.cm.gray)
plt.show()
์ด ์ค์ฐจ ํ๋ ฌ์ ๋๋ถ๋ถ์ ์ด๋ฏธ์ง๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋ถ๋ฅ๋์์์ ๋ํ๋ด๋ ์ฃผ๋๊ฐ์ ์ ์์นํ๋ฏ๋ก ๋งค์ฐ ์ข๊ฒ ๋ณด์ธ๋ค. (๋ฐฐ์ด์์ ๊ฐ์ฅ ํฐ ๊ฐ์ ํฐ์์ผ๋ก, ๊ฐ์ฅ ์์ ๊ฐ์ ๊ฒ์์์ผ๋ก ๋ํ๋จ)
๋ค๋ง ์ซ์ 5๋ ์๋์ ์ผ๋ก ์ด๋์ ๋ณด์ด๋๋ฐ, ์ด๋ 1) ๋ฐ์ดํฐ์ ์ ์ซ์ 5์ ์ด๋ฏธ์ง๊ฐ ์ ๊ฑฐ๋, ํน์ 2) ๋ถ๋ฅ๊ธฐ๊ฐ ์ซ์ 5๋ฅผ ๋ค๋ฅธ ์ซ์๋ณด๋ค ์ ๋ถ๋ฅํ์ง ๋ชปํ๋ค๋ ๋ป์ด๋ค. ์์ธ์ ํ์ธํ๊ธฐ ์ํด ์๋ฌ ๋น์จ์ ๋น๊ตํด๋ณธ๋ค.
์๋ฌ ๋น์จ ๋น๊ต
row_sums = conf_mx.sum(axis=1, keepdims=True)
norm_conf_mx = conf_mx / row_s๋ms
np.fill_diagonal(norm_conf_mx, 0) # ์ฃผ๋๊ฐ์ 0์ผ๋ก ์ฑ์
pit.matshow(norm_conf_mx, cmap=plt.cm.gray)
plt.show ()
ํ์ ์ค์ ํด๋์ค, ์ด์ ์์ธกํ ํด๋์ค๋ฅผ ๋ํ๋ธ๋ค.
์ ์ด๋ฏธ์ง์์ ๋ฐ์ ์ด(ํนํ 8, 9์ด)์ ๋ง์ ์ด๋ฏธ์ง๊ฐ ํด๋น ์ซ์๋ก ์๋ชป ์์ธก๋์์์, ๋ฐ์ ํ(ํนํ 8, 9ํ)์ ํด๋น ์ซ์๊ฐ ๋ค๋ฅธ ์ซ์๋ค๊ณผ ํผ๋์ด ์์ฃผ ๋๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
- ์ค์ฐจ ํ๋ ฌ ๋ถ์:
์ ๊ทธ๋ํ๋ฅผ ๋ถ์ํ๋ฉด ๋ถ๋ฅ๊ธฐ์ ์ฑ๋ฅ ํฅ์ ๋ฐฉ์์ ๋ํ ํต์ฐฐ์ ์ป์ ์ ์๋ค. ๊ฐ์ฅ ๋์ ๋๋ ๋ฐ์ ๋ถ๋ถ๋ค์ ๋ถ์ํด๋ณด๋ฉด ์๋์ ๊ฐ์ **๊ฐ์ ์ (๋ฌธ์ ์ )**์ ์ฐพ์ ์ ์๋ค.
- 3๊ณผ 5๊ฐ ์๋ก ํผ๋๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
- ๋ถ๋ฅ๊ธฐ๊ฐ 8, 9๋ฅผ ์ ๋ถ๋ฅํ์ง ๋ชปํ๋ค.
์ด์ ๋ํ ๊ฐ์ ๋ฐฉ์์ผ๋ก๋:
- ํ๋ จ ๋ฐ์ดํฐ๋ฅผ ๋ ๋ชจ์๋ค.
- ๋ถ๋ฅ๊ธฐ์ ๋์ ๋ ๋งํ ํน์ฑ์ ๋ ์ฐพ์๋ณธ๋ค.
- ์ด๋ค ํจํด์ด ๋๋ฌ๋๋๋ก (Scikit-Image, Pillow, OpenCV ๋ฑ์ ์ฌ์ฉํด์) ์ด๋ฏธ์ง๋ฅผ ์ ์ฒ๋ฆฌํ๋ค.
2. ๊ฐ๊ฐ์ ์๋ฌ ๋ถ์ : ๋ถ๋ฅ๊ธฐ๊ฐ ๋ฌด์จ ์ผ์ ํ๊ณ ์๊ณ , ์ ์๋ชป๋์๋์ง์ ๋ํด ํต์ฐฐ์ ์ป์ ์ ์๋ค.
๋จ, ๋ ์ด๋ ต๊ณ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฐ๋ค. ์์๋ก 3๊ณผ 5์ ์ํ์ ์ดํด๋ณธ๋ค.
- 3๊ณผ 5์ ์ํ ๊ทธ๋ฆฌ๊ธฐ:
cl_a, cl_b = 3, 5
X_aa = X_train[(y_train == cl_a) & (y_train_pred == cl_a)]
X_ab = X_train[(y_train == cl_a) & (y_train_pred == cl_b)]
X_ba = X_train[(y_train == cl_b) & (y_train_pred == cl_a)]
X_bb = X_train[(y_train == cl_b) & (y_train_pred == cl_b)]
p it.figure(figsize=(8,8))
plt.subplot(221); plot_digits(X_aa[:25], images_per_row=5)
plt.subplot(222); plot_digits(X_ab[:25], images_per_row=5)
plt.subplot(223); plot_digits(X_ba[:25], images_per_row=5)
plt.subplot(224); plot_digits(X_bb[:25], images_per_row=5)
plt.show()
์ผ์ชฝ์ ๋ธ๋ก ๋ ๊ฐ๋ 3์ผ๋ก, ์ค๋ฅธ์ชฝ ๋ธ๋ก ๋ ๊ฐ๋ 5๋ก ๋ถ๋ฅ๋ ์ด๋ฏธ์ง์ด๋ค. ์ผ์ชฝ ์๋ ๋ธ๋ก, ์ค๋ฅธ์ชฝ ์ ๋ธ๋ก์ ์๋ชป ๋ถ๋ฅ๋ ์ด๋ฏธ์ง๋ก ๋ถ๋ฅ๊ธฐ๊ฐ ์ค์ํ ๊ฒ์ด๋ค.
- ๋ถ์:
๋ถ๋ฅ๊ธฐ๊ฐ ์ค์ํ ์์ธ์ ์ ํ ๋ชจ๋ธ์ธ SGDClassifier๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ด๋ค.
์ ํ ๋ถ๋ฅ๊ธฐ๋ ํด๋์ค๋ง๋ค ํฝ์ ์ ๊ฐ์ค์น๋ฅผ ํ ๋นํ๊ณ ์๋ก์ด ์ด๋ฏธ์ง์ ๋ํด ๋จ์ํ ํฝ์ ๊ฐ๋์ ๊ฐ์ค์น ํฉ์ ํด๋์ค์ ์ ์๋ก ๊ณ์ฐํ๋ค. ์ด๋ 3๊ณผ 5๋ ๋ช ๊ฐ์ ํฝ์ ๋ง ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋ชจ๋ธ์ด ์ฝ๊ฒ ํผ๋ํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ด๋ฏธ์ง๋ฅผ ์ค์์ ์์น์ํค๊ณ ํ์ ๋์ด ์์ง ์๋๋ก ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ๋ค ์ ์๋ค. ๋ถ๋ฅ๊ธฐ๋ ์ด๋ฏธ์ง์ ์์น๋ ํ์ ๋ฐฉํฅ์ ๋งค์ฐ ๋ฏผ๊ฐํ๊ธฐ ๋๋ฌธ์ด๋ค.
3.6 ๋ค์ค ๋ ์ด๋ธ ๋ถ๋ฅ
1. ๋ค์ค ๋ ์ด๋ธ ๋ถ๋ฅ๋?
๋ค์ค ๋ ์ด๋ธ ๋ถ๋ฅ๋ ์ฌ๋ฌ ๊ฐ์ ์ด์ง ๋ ์ด๋ธ(ํด๋์ค)์ ์ถ๋ ฅํ๋ ๋ถ๋ฅ ์์คํ ์ ๋งํ๋ค. ํ ๊ฐ์ ์ํ์ ์ฌ๋ฌ ๊ฐ์ ์ด์ง ๋ ์ด๋ธ์ด ํ ๋น๋๋ ๊ฒ์ด๋ค.
2. ์์
ํ ๊ฐ์ ์ซ์ ์ด๋ฏธ์ง์ ๋ํด 1)ํฐ ๊ฐ(7, 8, 9)์ธ์ง, 2) ํ์์ธ์ง ์ฌ๋ถ๋ฅผ True, False์ ์ด์ง ๋ ์ด๋ธ๋ก์จ ํ๋ณํด์ฃผ๋ ๋ชจ๋ธ์ ํ๋ จ์ํค๊ณ ์์ธก์ ๋ง๋ค์ด๋ณธ ํ ์ฑ๋ฅ์ ํ๊ฐํด๋ณธ๋ค.
#๋ชจ๋ธ ํ๋ จ ๋ฐ ์์ธก
from sklearn.neighbors import KNeighborsClassifier
y_train_large = (y_train >= 7)
y_train_odd = (y_train % 2 == 1)
y_multilabel = np.c_[y_train_large, y_train_odd]
knn_crf = KNeighborsClassifier()
knn_clf.fit(X_train, y_multilabel)
# ์์ธก ๋ง๋ค๊ธฐ
knn_clf.predict([some_digit])
# ์ถ๋ ฅ๊ฐ(์ซ์ 5๋ฅผ ์
๋ ฅํ ๊ฒฝ์ฐ): array([[False, True]], dtype=bool)
- ๋ชจ๋ธ ํ๊ฐ : ๋ค์ค ๋ ์ด๋ธ ๋ถ๋ฅ๊ธฐ๋ฅผ ํ๊ฐํ๋ ์ ์ ํ ์งํ๋ ํ๋ก์ ํธ์ ๋ฐ๋ผ ๋ค๋ฅด๋ค. ์ด ๋ชจ๋ธ์ ๊ฒฝ์ฐ์๋ ๋ชจ๋ ๋ ์ด๋ธ์ ๋ํ F1 ์ ์์ ํ๊ท ์ ๊ณ์ฐํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด๋ณธ๋ค.
y_train_knn_pred = cross_val_predict(knn_clf, X_train, y_multilabel, cv=3,
n_jobs=-1)
f1_score(y_multilabel, y_train_knn_pred, average="macro")
# ์ถ๋ ฅ๊ฐ: 0.97709078477525
์ ์ฝ๋๋ ๋ชจ๋ ๋ ์ด๋ธ์ ๊ฐ์ค์น๊ฐ ๊ฐ๋ค๊ณ ๊ฐ์ ํ์์ผ๋ฏ๋ก f1_score์ ํ๋ผ๋ฏธํฐ average=”macro” ๋ก ์ค์ ํ์๋ค.
๊ฐ ๋ ์ด๋ธ์ ๊ฐ์ค์น์ ์ฐจ์ด๋ฅผ ๋๊ณ ์ถ๋ค๋ฉด average=”weighted”๋ก ์ค์ ํ๋ฉด ๋๋ค. ์ด๋ ๋ ์ด๋ธ์ ํด๋์ค์ ์ง์ง๋(ํ๊น ๋ ์ด๋ธ์ ์ํ ์ํ ์)๋ฅผ ๊ฐ์ค์น๋ก ์ฃผ๋ ๊ฒ์ ์๋ฏธํ๋ค.
3.7 ๋ค์ค ์ถ๋ ฅ ๋ถ๋ฅ
1. ๋ค์ค ์ถ๋ ฅ ๋ถ๋ฅ๋?
๋ค์ค ์ถ๋ ฅ ๋ถ๋ฅ, ํน์ ๋ค์ค ์ถ๋ ฅ ๋ค์ค ํด๋์ค ๋ถ๋ฅ๋ ๋ค์ค ๋ ์ด๋ธ ๋ถ๋ฅ์์ ํ ๋ ์ด๋ธ์ด ๋ค์ค ํด๋์ค๊ฐ ๋ ์ ์๋๋ก ์ผ๋ฐํํ ๊ฒ์ด๋ค. ์ฆ ์ฌ๋ฌ ๊ฐ์ ๋ค์ค ๋ ์ด๋ธ์ ์ถ๋ ฅํ ์ ์๋ค.
2. ์์
์ด๋ฏธ์ง์์ ๋ ธ์ด์ฆ๋ฅผ ์ ๊ฑฐํ๋ ์์คํ ์ ๋ง๋ค์ด๋ณธ๋ค. ํ ๊ฐ์ ์ ๋ ฅ(๋ ธ์ด์ฆ๊ฐ ๋ง์ ์ซ์ ์ด๋ฏธ์ง)์ ์ฌ๋ฌ ๊ฐ์ ๋ ์ด๋ธ(์ฌ๋ฌ ๊ฐ์ ํฝ์ )์ ๋ํด ์ฌ๋ฌ ๊ฐ์ ๊ฐ(0๋ถํฐ 255๊น์ง ํ์ ๊ฐ๋)์ ๊ฐ์ง๋ค.
๋จผ์ MNIST ์ด๋ฏธ์ง์์ ์ถ์ถํ ํ๋ จ ์ธํธ์ ํ ์คํธ ์ธํธ์ ๋ ธ์ด์ฆ๋ฅผ ์ถ๊ฐํ๋ค. ํ๊น ์ด๋ฏธ์ง๋ ์๋ณธ ์ด๋ฏธ์ง๊ฐ ๋๋ค.
noise = rnd.randint(0, 100, (len(X_train), 784)) # [0, 100)์ ๋ฒ์์์ (len(X_train), 784) ํํ์ ์์์ ์ ์ ๋ฐฐ์ด ์์ฑ
X_train_mod = X_train + noise
noise = rnd.randint(0, 100, (len(X_test), 784))
X_test_mod = X_test + noise
y_train_mod = X_train
y_test_mod = X_test
ํ
์คํธ ์ธํธ์์ ์ด๋ฏธ์ง๋ฅผ ํ๋ ์ ํํ๊ณ , ๋ถ๋ฅ๊ธฐ๋ฅผ ํ๋ จ์์ผ ์ด ์ด๋ฏธ์ง๋ฅผ ๊นจ๋ํ๊ฒ ๋ง๋ค์ด ๋ณธ๋ค. ๋ชฐ๋์ง ์์ฑํ ๋ชจ๋ธ์ ๊ณต๋ถํ๋ฉด์ ๋ค์ ์ด MNIST๋ฅผ ๋ง๋๊ฒ ๋ ๊ฑฐ๋ผ๊ณ ๋
knn_clf.fit(X_train_mod, y_train_mod)
clean_digit = knn_clf.predict([X_test_mod[some_index]])
plot_digit(clean_digit)
ํ๊น๊ณผ ๋งค์ฐ ๋น์ทํ๊ฒ ๊นจ๋ํ ์ด๋ฏธ์ง๋ก ์ ์ถ๋ ฅ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.