지도학습 ( 분류, 회귀 ), 평가지표 선택하는 방법
- 사용 이미지들 -
사용된 이미지가 많으므로 pdf 파일을 다운로드 받아서 봐야한다
실습 예제 모음
혹시 몰라 HTML 형식으로도 업로드...
머신러닝 종류¶
- 지도학습 알고리즘
- 주요 목적은 레이블(정답)이 있는 훈련 데이터로 모델을 학습하여 예측할 때 사용
- 분류(classification)
- 독립변수(문제)에 의하여 종속변수(정답)가 딱 떨어지는 값일 때
- 예) 스펨메일, 은행에서 대출 승인/거절, 생존 중 살았다/죽었다. 등..
- 회귀(regression)
- 임의의 숫자를 맞추는 것.
- 어떤 사람의 나이, 농작물의 수확량, 주가 가격 등을 예측
In [ ]:
In [ ]:
사이킷 런¶
- 사이킷런은 파이썬 머신러닝 라이브러리 중 가장 많이 사용되는 라이브러리
- 파이썬 기반의 머신러닝을 위한 가장 쉽고 효율적인 개발 라이브러리를 제공
- 많은 사용자 들이 사용하는 라이브러리로 검증되어 있다
알고리즘 선택 방법¶
- 사이킷런에서 알고리즘 선택방법을 제시하고 있다
- https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html
In [ ]:
In [ ]:
Kneighbors(K-최근접 이웃 알고리즘)¶
- 주위의 가장 가까운 다른 데이터를 보고 현재 데이터를 판단
- 기본 비교 개수는 5개로 되어 있다
- 비교 개수를 변경하고자 할 경우 n_neighbors에 값 지정
In [ ]:
In [ ]:
Ensemble(앙상블)¶
- 여러 개의 분류기(알고리즘)를 생성하고 그 예측을 결합함으로써 보다 정확한 분류기 생성
- 앙상블의 대표 알고리즘은 랜덤포레스트와 그래디언트부스팅이 있다
- 앙상블 학습의 유형
- 보팅(Voting) : 서로 다른 알고리즘을 가진 분류기를 결합하여 사용
- 배깅(Bagging) : 모두 같은 유형의 알고리즘을 가진 분류기를 결합하여 사용
- 대표적 알고리즘인 랜덤포레스트가 있다
- 부스팅(Boosting) : 오류를 개선해 나가면서 학습하는 방식(다른 알고리즘에 비해 시간이 더 걸림)
In [ ]:
In [ ]:
train_test_split¶
- 데이터를 알고리즘에 사용하고자 하는경우 속성(feature)과 정답(label) 구분을 해야 한다.
- 알고리즘에 학습하기 위해 test data 와 train data를 구분하여 사용한다.
- 70% train(학습)데이터, 30% test 데이터(실제 데이터로 가정하여 확인)
- 20% test 데이터 , 80% -> 20%(validation)검증, 80% 학습데이터
In [ ]:
In [ ]:
사과 품질 분류하기¶
- 컬럼
- Size : 크기
- Weight : 무게
- Sweetness : 단맛
- Crunchiness : 아삭한 정도
- Juiciness : 사과 즙의 정도
- Ripeness : 사과의 숙성 정도
- Acidity : 신맛
- Quality : 품질
In [5]:
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
In [6]:
df = pd.read_csv("../data_set/4.분류/apple_quality.csv")
df.head()
Out[6]:
A_id | Size | Weight | Sweetness | Crunchiness | Juiciness | Ripeness | Acidity | Quality | |
---|---|---|---|---|---|---|---|---|---|
0 | 0.0 | -3.970049 | -2.512336 | 5.346330 | -1.012009 | 1.844900 | 0.329840 | -0.491590483 | good |
1 | 1.0 | -1.195217 | -2.839257 | 3.664059 | 1.588232 | 0.853286 | 0.867530 | -0.722809367 | good |
2 | 2.0 | -0.292024 | -1.351282 | -1.738429 | -0.342616 | 2.838636 | -0.038033 | 2.621636473 | bad |
3 | 3.0 | -0.657196 | -2.271627 | 1.324874 | -0.097875 | 3.637970 | -3.413761 | 0.790723217 | good |
4 | 4.0 | 1.364217 | -1.296612 | -0.384658 | -0.553006 | 3.030874 | -1.303849 | 0.501984036 | good |
In [7]:
df["Quality"].unique()
Out[7]:
array(['good', 'bad', nan], dtype=object)
In [10]:
df.isnull().sum()
Out[10]:
A_id 1 Size 1 Weight 1 Sweetness 1 Crunchiness 1 Juiciness 1 Ripeness 1 Acidity 0 Quality 1 dtype: int64
In [11]:
df.shape
Out[11]:
(4001, 9)
In [12]:
# 결측치가 있는 행을 모두 삭제
df.dropna(axis=0, inplace=True)
In [14]:
# 삭제 완료
df.isnull().sum()
Out[14]:
A_id 0 Size 0 Weight 0 Sweetness 0 Crunchiness 0 Juiciness 0 Ripeness 0 Acidity 0 Quality 0 dtype: int64
In [15]:
df.columns
Out[15]:
Index(['A_id', 'Size', 'Weight', 'Sweetness', 'Crunchiness', 'Juiciness', 'Ripeness', 'Acidity', 'Quality'], dtype='object')
In [17]:
# 변수 ( features )
f = ['Size', 'Weight', 'Sweetness', 'Crunchiness', 'Juiciness',
'Ripeness', 'Acidity']
# 정답 ( label )
l = 'Quality'
X, y = df[f], df[l]
X, y
Out[17]:
( Size Weight Sweetness Crunchiness Juiciness Ripeness \ 0 -3.970049 -2.512336 5.346330 -1.012009 1.844900 0.329840 1 -1.195217 -2.839257 3.664059 1.588232 0.853286 0.867530 2 -0.292024 -1.351282 -1.738429 -0.342616 2.838636 -0.038033 3 -0.657196 -2.271627 1.324874 -0.097875 3.637970 -3.413761 4 1.364217 -1.296612 -0.384658 -0.553006 3.030874 -1.303849 ... ... ... ... ... ... ... 3995 0.059386 -1.067408 -3.714549 0.473052 1.697986 2.244055 3996 -0.293118 1.949253 -0.204020 -0.640196 0.024523 -1.087900 3997 -2.634515 -2.138247 -2.440461 0.657223 2.199709 4.763859 3998 -4.008004 -1.779337 2.366397 -0.200329 2.161435 0.214488 3999 0.278540 -1.715505 0.121217 -1.154075 1.266677 -0.776571 Acidity 0 -0.491590483 1 -0.722809367 2 2.621636473 3 0.790723217 4 0.501984036 ... ... 3995 0.137784369 3996 1.854235285 3997 -1.334611391 3998 -2.229719806 3999 1.599796456 [4000 rows x 7 columns], 0 good 1 good 2 bad 3 good 4 good ... 3995 bad 3996 good 3997 bad 3998 good 3999 good Name: Quality, Length: 4000, dtype: object)
In [18]:
from sklearn.model_selection import train_test_split
# 학습용 70프로 할당
# 테스트용 30프로 할당
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
In [20]:
print("총 갯수 : ", X.shape, y.shape)
print("학습 갯수 : ", X_train.shape, y_train.shape)
print("테스트 갯수 : ", X_test.shape, y_test.shape)
총 갯수 : (4000, 7) (4000,) 학습 갯수 : (2800, 7) (2800,) 테스트 갯수 : (1200, 7) (1200,)
In [23]:
from sklearn.neighbors import KNeighborsClassifier
kn = KNeighborsClassifier()
# 문제와 정답 학습시키기
kn.fit(X_train, y_train)
# 테스트용으로 예측한 정답과 실제 정답을 비교한
# 정답률을 확인
# 90% 정답률 확인
kn.score(X_test, y_test)
Out[23]:
0.9083333333333333
In [ ]:
In [ ]:
SVM(Support Vector Machine)¶
- 특정 데이터들을 구분하는 선을 찾고, 이를 기반으로 패턴을 인식하는 방법
- kernel : linear, rbf
- linear : 선형으로 데이터들을 구분지을 수 있는 경우
- rbf : 선형으로 데이터를 구분지을 수 없는 경우
In [29]:
import sklearn.svm as svm
# linear(선형) 구조로 알고리즘을 학습
svm_linear = svm.SVC(kernel="linear")
# SVM 알고리즘을 사용하여 학습
svm_linear.fit(X_train, y_train)
# 테스트 결과
svm_linear.score(X_test, y_test)
Out[29]:
0.7516666666666667
In [30]:
import sklearn.svm as svm
# rbf(비선형) 구조로 알고리즘을 학습
svm_linear = svm.SVC(kernel="rbf")
# SVM 알고리즘을 사용하여 학습
svm_linear.fit(X_train, y_train)
# 테스트 결과
svm_linear.score(X_test, y_test)
Out[30]:
0.9091666666666667
In [31]:
# 학습 결과 비선형 알고리즘이 해당 데이터에서는
# 더 정확한 예측 값을 가져오므로 비선형 알고리즘을
# 사용해야 한다.... 라는 결론 도출
In [ ]:
In [ ]:
DecisionTree¶
- 특정 조건에 따라 가지치기 과정을 반복하면서 모델을 생성한다
In [33]:
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier()
# 학습
dt.fit(X_train, y_train)
# 정확도 확인
dt.score(X_test, y_test)
Out[33]:
0.82
In [ ]:
In [ ]:
Voting(보팅)¶
- 하드보팅(Hard Voting) : 다수의 결정에 의해 결과값이 선정된다
- 소프트보팅(Soft Voting) : 결정된 값들의 평균을 구하고 가장 높은 값을 선정
- 일반적으로 하드보팅보다 소프트 보팅이 성능이 좋아 소프트 보팅을 많이 사용한다
In [35]:
# probability=True : soft voting 시 참, 거짓이 아닌 확률을 참 : 70%, 거짓 : 30%
# 확률로 나타내준다
s = svm.SVC( kernel="rbf", probability=True )
s.fit(X_train, y_train)
k = KNeighborsClassifier()
k.fit(X_train, y_train)
d = DecisionTreeClassifier()
d.fit(X_train, y_train)
Out[35]:
DecisionTreeClassifier()In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
DecisionTreeClassifier()
In [40]:
from sklearn.ensemble import VotingClassifier
# VotinClassifier 객체를 생성하여 각 알고리즘을 추합해서
# 알고리즘의 예측 값들을 가져와 결론을 도출할 수 있다
# soft voting 설정
vo = VotingClassifier( estimators=[("svc",s), ("knn",k), ("DecisionTree",d)], voting="soft")
vo.fit(X_train, y_train)
print("svm : ", s.score(X_test, y_test))
print("kn : ", k.score(X_test, y_test))
print("d : ", d.score(X_test, y_test))
print("vo : ", vo.score(X_test, y_test))
svm : 0.9091666666666667 kn : 0.9083333333333333 d : 0.8125 vo : 0.8933333333333333
In [41]:
# VotinClassifier 객체를 생성하여 각 알고리즘을 추합해서
# 알고리즘의 예측 값들을 가져와 결론을 도출할 수 있다
# hard voting 설정
vo = VotingClassifier( estimators=[("svc",s), ("knn",k), ("DecisionTree",d)], voting="hard")
vo.fit(X_train, y_train)
print("svm : ", s.score(X_test, y_test))
print("kn : ", k.score(X_test, y_test))
print("d : ", d.score(X_test, y_test))
print("vo : ", vo.score(X_test, y_test))
svm : 0.9091666666666667 kn : 0.9083333333333333 d : 0.8125 vo : 0.9075
In [ ]:
In [ ]:
RandomForest(랜덤포레스트)¶
- decision tree 알고리즘을 여러 개의 분류기로 만들어서 보팅(소프트보팅)으로 최종 결정한다
In [43]:
from sklearn.ensemble import RandomForestClassifier
# 모델 생성
rfc = RandomForestClassifier()
# 모델 학습
rfc.fit(X_train, y_train)
# 학습 결과 테스트
rfc.score(X_test, y_test)
Out[43]:
0.8991666666666667
In [ ]:
In [ ]:
부스팅(Boosting)¶
- GBM(Gradient Boosting Machine)
- decision tree를 묶어 강력한 model을 만드는 ensemble기법입니다.
- 순차적으로 학습-예측하면서 잘못 예측한 데이터의 오류를 개선해 나가면서 학습하는 방법
- 다른 알고리즘에 비해 처리속도가 느림
In [44]:
from sklearn.ensemble import GradientBoostingClassifier
# 모델 생성
gbc = GradientBoostingClassifier()
# 모델 학습
gbc.fit(X_train, y_train)
# 학습 결과 테스트
gbc.score(X_test, y_test)
Out[44]:
0.8666666666666667
In [ ]:
In [ ]:
In [45]:
df.head(2)
Out[45]:
A_id | Size | Weight | Sweetness | Crunchiness | Juiciness | Ripeness | Acidity | Quality | |
---|---|---|---|---|---|---|---|---|---|
0 | 0.0 | -3.970049 | -2.512336 | 5.346330 | -1.012009 | 1.844900 | 0.32984 | -0.491590483 | good |
1 | 1.0 | -1.195217 | -2.839257 | 3.664059 | 1.588232 | 0.853286 | 0.86753 | -0.722809367 | good |
In [49]:
s.predict([[-3.970049, -2.512336, 5.346330, -1.012009, 1.844900, 0.32984, -0.491590483]])
Out[49]:
array(['good'], dtype=object)
In [ ]:
In [ ]:
Classification Metric¶
- Metric : 학습을 통해 목표를 얼마나 잘(못) 달성했는지를 나타내는 값을 척도(metric)라고 합니다
- Accuracy(정확도)
- 전체 샘플 중 맞게 예측한 샘플 수의 비율
- Recall(재현율)
- 양성 샘플을 양성으로 맞춘 비율과 양성을 음성으로 잘못 예측한 비율
- 실제 음성을 양성으로 잘못 맞춰도 재현율은 떨어지지 않는다
- Precision(정밀도)
- 양성이라고 예측한 값의 비례하는 실제 값이 양성인 비율
- 음성을 양성으로 잘못 판단하면 정밀도는 떨어진다
- F1 - score
- Reacll과 Precision의 조화평균
- Accuracy(정확도)
Accuracy(정확도)¶
- 전체 샘플 중 맞게 예측한 샘플 수의 비율을 뜻한다.
- 즉, 전체 개수 중 정답을 맞춘 개수이다.
- 10문제 중 8개 맞추면 80% 맞춘 결과가 나온다
- accuracy는 label의 값이 균등할 때 사용하면 된다.
In [50]:
y_test = [0,1,1,0,0,0,1,1,1,1] #실제 정답
y_pred = [1,0,0,0,0,0,1,1,1,1] #예측 정답
In [53]:
from sklearn.metrics import accuracy_score
# 단순히 몇개를 맞췄는지 확인하는 accuracy_score
# 아래와 같이 사용하면 % 로 정답률을 알려줌
acc = accuracy_score(y_test, y_pred)
acc
Out[53]:
0.8
In [55]:
# 암인지 아닌지에 대한 Dataset
# 1 : 암에 걸림, 0 : 암에 걸리지 않음
y_test = [1,1,0,1,1,1,1,1,1,1] #실제 정답
y_pred = [0,1,1,1,1,1,1,1,1,1] #예측 정답
In [57]:
# 80% 정답률을 확인
acc = accuracy_score(y_test, y_pred)
acc
Out[57]:
0.8
In [ ]:
In [ ]:
재현율(recall)¶
- 실제 양성 샘플을 양성으로 맞춘 비율과 양성을 음성으로 잘못 예측한 비율
- 높을 수록 좋은 모델
- 양성(1)이 중요한 경우
In [62]:
y_test = [0,0,0,1,1,1,1,1,1,1] #실제 정답
y_pred = [1,1,1,1,1,1,1,1,1,1] #예측 정답
In [64]:
from sklearn.metrics import recall_score
# 모델 생성 및 훈련
recall = recall_score(y_test, y_pred)
recall
# 실제 정답이 1 즉, 의미 있는 결과 값이 나온것에 대한
# 정답률만을 출력....
# 0 에 대한 정답률은 출력하지 않음
# 고로 0 : 암에 걸리지 않음, 1 : 암에 걸림 이라면
# 암에 걸린 사람들에 대한 예측 결과만 100% 로 맞추고
# 암에 걸리지 않은 사람들에 대한 예측결과는 50% 로 맞췄다면
# 결과는 100% 로 출력된다
Out[64]:
1.0
In [65]:
y_test = [1,1,1,1,1,1,1,1,1,1] #실제 스팸 문자
y_pred = [0,0,0,1,1,1,1,1,1,1] #예측 스팸 문자
recall = recall_score(y_test, y_pred)
recall
Out[65]:
0.7
In [67]:
y_test = [0,0,0,1,1,1,1,1,1,1] #실제 스팸 문자
y_pred = [1,1,1,1,1,1,1,1,1,1] #예측 스팸 문자
recall = recall_score(y_test, y_pred)
recall
# 메일의 경우는 recall 로 처리하면 안된다...
# 정답률이 100% 로 나오기 때문에 실제 스팸 문자가 아닌데
# 스팸 문자로 처리될 수 있기 때문...!!!
Out[67]:
1.0
In [ ]:
In [ ]:
정밀도(precision)¶
- 실제 음성의 값을 못맞추는 경우 예측력이 떨어진다\
In [70]:
y_test = [1,1,1,1,1,1,1,1,1,1] #실제 스팸 문자
y_pred = [0,0,0,1,1,1,1,1,1,1] #예측 스팸 문자
In [72]:
from sklearn.metrics import precision_score
p = precision_score(y_test, y_pred)
p
# 정밀도를 기준으로 판단은 예측 값이 1인 경우의 정답률만을 확인
# 고로, 예측한 스팸 문자가 실제로 스팸문자 인지만 확인하여
# 정답률을 출력한다....
# 스팸메일이 아닌 문자로 예측한 문자에 대한 정답률은 확인하지 않는다
Out[72]:
1.0
In [76]:
y_test = [0,0,1,1,1,1,1,1,1,1] #실제 스팸 문자
y_pred = [1,1,0,1,1,1,1,1,1,1] #예측 스팸 문자
p = precision_score(y_test, y_pred)
p
# 스팸문자라고 예측한 값이 실제 스팸문자가 아닌 경우가 생겼기 때문에
# 예측 정답률이 1.0 이 아니게 된다
Out[76]:
0.7777777777777778
In [ ]:
In [ ]:
In [77]:
y_test = [0,0,1,1,1,1,1,1,1,1] #실제 스팸 문자
y_pred = [1,1,1,1,1,1,1,1,1,1] #예측 스팸 문자
In [80]:
from sklearn.metrics import f1_score
acc = accuracy_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
pre = precision_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
print("accuracy(정확도) : ", acc)
print("recall(재현율) : ", recall)
print("precision(정밀도) : ", pre)
print("f1 score : ", f1)
# f1 은 recall 과 precision 의 결과를 혼합해서 정답률을 출력한다
accuracy(정확도) : 0.8 recall(재현율) : 1.0 precision(정밀도) : 0.8 f1 score : 0.888888888888889
In [ ]:
평가지표 선택하기¶
- accuracy : label값이 편향되어 있지 않은 경우
- f1_score : label값이 편향되어 있는 경우
정답 값이 편향되어 있는 경우 f1_score 을 사용
정답 값이 편향되어 있지 않고 42% : 58% 같이 균형을 이룬 경우 accuracy 사용경우
728x90
'BE > 머신러닝(ML)' 카테고리의 다른 글
[머신러닝] 회귀 및 평가지표 (0) | 2024.05.27 |
---|---|
[머신러닝] 과적합 및 하이퍼파라미터 (0) | 2024.05.27 |
[머신러닝] 탐색적 데이터분석 ( EDA, 표준화, 가중치 ) (0) | 2024.05.24 |
[머신러닝] 시각화 ( mataplotlib, seaborn ) (0) | 2024.05.24 |
[머신러닝] 실습 예제 및 풀이 (1) | 2024.05.23 |