🔍머신러닝 4일차
👨🏫 질의응답 시간!
💡 kNN 모델 성능을 높이기 위한 방법
- MinMaxScaler
- StandardScaler
- MaxAbsScaler
- BobustScaler 등등
이 많은 스케일링 중에 수업시간에는 한정된 시간을 고려하여 MinMaxScaler를 사용하는 것이지, MinMax 정규화를 사용할 것을 강조한 것은 아니다. 또한, 우리 입장에서는 독립변수가 1개인 경우 스케일링을 진행할 필요없다.
❓❗ x_train, x_test만 스케일링을 하고 y는 왜 하지 않는건가요?
우리가 예측해야 하는 타겟인 y는 독립변수들 값에 따른 거리를 비교해 최근접 이웃을 골라 예측하기 때문에 스케일링 하지 않는다.
💡 선형회귀 모델을 이용해서 도출한 회귀선(가중치, 편향)과 seaborn패키지의 regplot으로 그린 회귀선은 항상 같은 것이다. 우리는 회귀선을 도출하는 과정을 배우기 위해 따로 그려주는 것.
❓❗ speed = np.array [x_train.min(), x_train.max()] 하면 [4,25]가 왜 안나오나요?
저렇게 하면 [[4]
[25]]가 나왔을 것.
speed = np.array ([x_train.min()[0], x_train.max()[0]])하면 [ 4 25]가 나온다.
x_train.min() 이 시리즈이기 때문에
❓❗ 범주형 변수를 일일이 변수에 저장할 수 없을 때, 혹시 범주형 변수만을 따로 추출해서 변수에 담아 더미 변수화를 할 수 있는 방법이 있을까요?
#1. 범주형 변수는 대부분 str이므로
x = pd.get_dummies(x, columns = dumm_cols, drop_first = True)에서 columns = dumm_cols,를 지우고,
x = pd.get_dummies(x,drop_first = True) 라고 입력하면 object형 변수를 모두 가변수화한다는 뜻!
#2. object 형 변수 이름 얻기
x.dtypes를 하면 object들을 알 수 있다.
이를 cols로 선언하고 ( cols = x.dtypes)
dumm_cols = list(cols.loc[cols.values == 'object'].index)
그리고 나서 x = pd.get_dummies(x, columns = dumm_cols, drop_first = True)를 해주면 된다.
이후 필요하다면 dumm_cols.append('Education')으로 해서 추가해주면 된다.
❓❗ 모델이 유의미한지 알려면 회귀계수의 t통계량의 p-v를 보고 유의미한지 봐야한다고 알고 있는데 회귀계수의 유의미와 별개로 그냥 r2_score만 보고 설명력을 따지고 넘어가는 게 맞나요?
회귀계수의 유의성을 따지는 것은 너무 통계적이다. 우리는 한정된 시간으로 인해 통계를 깊이 있게 들어갈 수 없고, 깊이있게 따져볼 수 없다.
❓❗ x_train에 대한 스케일링을 하는 것은 스케일링을 통해 feature들의 데이터 범위를 같게 하기 위함이라고 이해를 했습니다. 그렇다면 x_test에 대한 스케일링이 y_pred를 구할 때, feature들의 데이터 범위를 같게 하기 위해서 스케일링을 진행한다고 이해하면 될까요?
위 질문말고도 더 많은 질문이 있었지만 내가 다 담아내지 못 했다. 같은 에이블러이고 같은 수업을 들었는데 다 다른 생각을 한다는 것이 새삼 신기하다. 매번 많은 것을 얻어가는 질의응답시간이다.
질문해주신 🐛에이블러분들에게 정말 감사하다. ❤
💻 kNN 분류문제(실습03_04_KNN(Attrition))
📌 target(Attrition)에 대한 값 분포 확인
# target 값 분포 확인
data['Attrition'].value_counts() # 불균형 클래스
# 이직한 사람보다 안한 사람이 더 많음. 정확도는 나쁘지 않을 것이다는 걸 예측할 수 있다.
# 1에 대한 성능이 낮다. 1의 precision과 recall이 낮을 것. 하지만 0이 높으므로 accuracy는 높을 것
📌 변수 제거
# 제거 대상: EmployeeNumber
drop_cols = ['EmployeeNumber']
# 변수 제거
data.drop(drop_cols, axis = 1, inplace = True)
# 확인
data.head()
📌 x,y분리
# target 확인
target = 'Attrition'
# 데이터 분리
x = data.drop(target, axis=1)
y = data.loc[:,target]
📌 가변수화
# 확인
x.info()
# 가변수화 대상: Gender, JobSatisfaction, MaritalStatus, OverTime
dumm_cols = ['Gender', 'JobSatisfaction', 'MaritalStatus', 'OverTime']
# 가변수화
x = pd.get_dummies(x, columns = dumm_cols, drop_first = True)
# 확인
x.info()
📌학습용, 평가용 데이터 분리
# 모듈 불러오기
from sklearn.model_selection import train_test_split
# 데이터 분리
x_train, x_test, y_train, y_test = train_test_split(x,y,test_size=0.3,random_state=1)
📌 정규화
# 확인
x_train.head(5)
# 모듈 불러오기
from sklearn.preprocessing import MinMaxScaler
# 정규화
scaler = MinMaxScaler()
scaler.fit(x_train)
# fit하기 = x_train의 최솟값/최댓값 찾기, 정규화 기반 쌓기
x_train = scaler.transform(x_train)
# fit한 결과를 바탕으로 x_train 실제 정규화 수행
x_test = scaler.transform(x_test)
# fit한 결과를 바탕으로 x_test 실제 정규화 수행
# 결과
x_train # 배열이므로 x_train.head(5)하면 오류남.
💡kNN분류문제에서의 정규화 모듈 불러오기
from sklearn.preprocessing import MinMaxScaler
💡x_train = scaler.fit_transform(x_train) # fit과 transform을 한번에 한다.
x_test = scaler.transform(x_test)
# x_test = scaler.transform(x_test)에는 fit_transform을 하면 안된다. fit은 x_train만 해주는 것.
⭐ 잘 기억할 것
1. 평가(미래)데이터가 학습(현재)데이터에 영향을 못 미친다.
2. 평가데이터를 정규화할 때는 학습데이터의 규칙을 그대로 적용한다.
📌 모델링
# 1단계: 불러오기
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix, classification_report, r2_score
# 2단계: 선언하기
model = KNeighborsClassifier()
# 3단계: 학습하기
model.fit(x_train,y_train)
# 4단계: 예측하기
y_pred = model.predict(x_test)
💡여기 분류문제인 KNeighborsClassifier에서 r2_score가 되는 이유는 0과 1을 연속된 값으로 보기 때문.
하지만 r2_score는 분류문제에서는 전혀 의미가 없다. 이 점을 주의할 것.
따라서 위 r2_score는 지워주어야 한다.
잠깐❗) 분류 => from sklearn.metrics import confusion_matrix, classification_report
회귀 => from sklearn.metrics import mean_absolute_error, r2_score
# 내가 한 것.
# 5단계: 평가하기
print(accuracy_score(y_test,y_pred))
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
print(precision_score(y_test,y_pred))
print(recall_score(y_test,y_pred))
print(classification_report(y_test,y_pred)) # precision과 recall을 할 필요 없다.
print(confusion_matrix(y_test,y_pred))
# 이장래 강사님께서 하신 것.
# 5단계: 평가하기
print(classification_report(y_test,y_pred))
print(confusion_matrix(y_test,y_pred))
# 여기서 정확도는 높지만 1의 recall이 많이 낮은 것을 볼 수 있다.
📕 Decision Tree(결정 트리, 의사결정 나무)
- 특정 변수에 대한 의사결정 규칙을 나무 가지가 뻗는 형태로 분류해 나간다.
- 분류와 회귀 모두에 사용되는 지도학습 알고리즘이다.
분석 과정이 직관적이며, 이해와 설명하기가 쉬움.
스케일링 등의 전처리 영향도가 크지 않음.
분석 과정을 실제로 눈으로 확인할 수 있음 → 화이트박스 모델
- 스무고개와 비슷하게 의미 있는 질문을 먼저 하는 것이 중요.
- 과적합으로 모델 성능이 떨어지기 쉬움 → 트리 크기를 제한하는 튜닝이 필요
- 정보이득이 가장 큰 변수를 선택
- 확률에 근거해 예측을 한다.
📌불순도(Impurity)
- 순도의 반대말
- 불순도는 0과 0.5 사이(불순도가 가장 높은 것은 0.5)
- 불순도를 수치화 할 수 있는 지표=> 지니 불순도(Gini Impurity), 엔트로피(Entropy)
📌 지니 불순도(Gini Impurity) : 대표적인 불순도 수치화 지표
- 분류 후에 얼마나 잘 분류했는지 평가하는 지표
(얼마나 순도가 증가했는지, 불순도가 감소했는지)
- 이진 분류로 나뉠 때 사용됨
- 지니 불순도가 낮을수록 순도가 높음
- 지니 불순도는 0(순수,완벽하게 분류)과 0.5( 50:50으로 섞임)사이의 값 (이진 분류의 경우)
지니 불순도가 낮은 속성으로 의사결정 트리 노드 결정.
💡 gini = 0.66❓
- 분류해야할 값이 2개인 경우에만 0.5가 최대!
분류해야할 값이 3개인 경우 0.5보다 큰 값이 나올 수 있다.
📌 정보 이득(Information Gain)
- 우리가 알고 싶은 것 = 정보 이득 = 어떤 속성이 얼마나 많은 정보를 제공하는가
엔트로피는 단지 속성의 불순도를 표현
- 정보 이득이 크다 = 어떤 속성에서 분할할 때 불순도가 줄어든다.
모든 속성에 대해 분할한 후 정보 이득 계산
정보 이득이 가장 큰 속성부터 분할한다.
- 정보 이득 = 부모의 불순도 - 자식의 불순도
자식 중 한 자식의 불순도가 더 클 수도 있다.
하지만 가중치를 계산해보면 자식 전체의 불순도는 크지 않다.
📌 가지치기
- 가지치기를 하면 학습 데이터에 대한 성능은 낮아지지만, 평가데이터에 대한 성능을 높일 수 있다.
가지치기를 하지 않으면 모델이 학습 데이터에는 매우 잘 맞지만, 평가데이터에는 잘 맞지 않을 수 있다.
→ 과대적합, 일반화되지 못함.
- 여러 하이퍼파라미터 값을 조정해서 가지치기 할 수 있다.
가장 적절한 하이퍼파라미터 값을 찾도록 노력해야한다.
📌 주요 하이퍼파라미터
✔ max_depth(대표적인 하이퍼파라미터)
- 트리의 최대 깊이(기본값:None)
- 값이 클수록 더 깊이있게 분할
- 계속 분할되면 트리 깊이가 너무 깊어져 과적합이 발생할 수 있으니 적절한 값 설정 필요
✔ min_samples_split - 값이 작을수록 더 깊이 있게 분할
✔ min_samples_leaf - 값이 작을수록 더 깊이 있게 분할
✔ max_feature
✔ max_leaf_node
💻 Decision Tree 분류문제(ML03_03_Decision Tree(Attrition))
📌 변수제거
# 제거 대상: PassengerId, Name, Ticket, Cabin
drop_cols = ['PassengerId', 'Name', 'Ticket', 'Cabin']
# 변수 제거
data.drop(drop_cols, axis=1, inplace=True)
# 확인
data.head()
📌 결측치 처리
# Age 결측치를 중앙값으로 채우기
age_median = data['Age'].median()
data['Age'].fillna(age_median, inplace=True)
# Embarked 최빈값으로 채우기
emb_freq = data['Embarked'].mode()[0]
data['Embarked'].fillna(emb_freq, inplace=True)
📌 x,y분리
# target 확인
target = 'Survived'
# 데이터 분리
x = data.drop(target, axis=1)
y = data.loc[:, target]
📌 범주형 변수에 대한 가변수화
# 확인
x.info()
# 가변수화 대상: Pclass, Sex, Embarked
dumm_cols = ['Pclass', 'Sex', 'Embarked']
# 가변수화
x = pd.get_dummies(x, columns=dumm_cols, drop_first=True)
# columns=dumm_cols가 없이 get_dummies를 하면 Pclass는 int이므로 가변수화가 안된다.
# 확인
x.head()
📌 학습용, 평가용 데이터 분리
# 모듈 불러오기
from sklearn.model_selection import train_test_split
# 7:3으로 분리
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)
📌 모델링
# 1단계: 불러오기
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import confusion_matrix, classification_report
# 2단계: 선언하기
model = DecisionTreeClassifier(random_state=1)
# 3단계: 학습하기
model.fit(x_train,y_train)
# 4단계: 예측하기
y_pred = model.predict(x_test)
# 5단계 평가하기
print(confusion_matrix(y_test,y_pred))
print(classification_report(y_test,y_pred))
💡 2단계 선언하기 model = DecisionTreeClassifier(random_state=1)에서
model = DecisionTreeClassifier(max_depth=5 ,random_state=1) 를 넣어주었을 때,
5단계까지만 분류를 진행한다.
📌트리 시각화
# 시각화 모듈 불러오기
from sklearn.tree import export_graphviz
from IPython.display import Image
# 이미지 파일 만들기
export_graphviz(model, # 모델 이름
out_file='tree.dot', # 파일 이름
feature_names=x.columns, # Feature 이름(list(x)써도 됨.)**
class_names=['die', 'survived'], # Target Class 이름**
rounded=True, # 둥근 테두리
precision=2, # 불순도 소숫점 자리수
max_depth=5, # 보고싶은 Tree 깊이 설정
filled=True) # 박스 내부 채우기
# 파일 변환
!dot tree.dot -Tpng -otree.png -Gdpi=300
# 이미지 파일 표시
Image(filename='tree.png')
- 불순도가 낮을수록(0에 가까울수록) 진한 배경색
💡** Feature 이름과 Target Class 이름만 바꿀 수 있다.
Target Class 이름(class_names=[' '])의 경우 회귀에서는 제외, 회귀는 class가 아니니까)
⭐ class_names=[ 'No', 'Yes' ])의 경우 0과 1을 잘 고려해서 넣을 것!
💡 이미지 파일 만들기에서 export_graphviz(model, max_depth=5, ...)를 넣으면
이미지 파일에 5단계의 가지만 그려진다.
💡!dot tree.dot -Tpng -otree.png -Gdpi=300 이 줄은 마음대로 띄어쓰면 안된다.
ex) -Gdpi = 300 이렇게하면 오류남.
-Gdpi 300이면 고해상도이다. 기본값이 90정도 밖에 안되므로
💡이미지 파일 이름을 바꿔주려면 여기 표시되어 있는 부분 전부 바꿔주어야한다.
# 이미지 파일 만들기
export_graphviz(model, # 모델 이름
out_file='tree.dot', # 파일 이름
feature_names=x.columns, # Feature 이름 (list(x)써도 됨.)**
class_names=['die', 'survived'], # Target Class 이름**
rounded=True, # 둥근 테두리
precision=2, # 불순도 소숫점 자리수
max_depth=5, # 보고싶은 Tree 깊이
filled=True) # 박스 내부 채우기
# 파일 변환
!dot tree.dot -Tpng -otree.png -Gdpi=300
# 이미지 파일 표시
Image(filename='tree.png')
💡 sklearn에 플롯트리(plot_tree)도 있지만 플롯트리는 가독성이 떨어진다.
강사님이 그래프비즈(graphviz)를 더 좋아하심 😊
📌변수 중요도 시각화
# 변수 중요도 시각화
plt.figure(figsize=(6,8))
plt.barh(list(x),model.feature_importances_)
plt.ylabel('Features')
plt.xlabel('Importances')
plt.show()
- Feature 순서대로 값을 가짐.
- 트리 구성에 중요한 역할을 한 변수를 시각화해서 확인할 수 있음.
- plt.barh(y = list(x), width = model.feature_importances_)
- sns.barplot(y = list(x), x = model.feature_importances_)
seaborn은 x와 y의 위치를 바꾸면 막대그래프가 가로로 나온다.
💡 변수 중요도를 얻고자 Decision Tree를 쓰지 마라.
Decision Tree를 쓰는 목적은 변수 중요도를 알아보기 위한 것이 아니다.
Decision Tree를 쓰게 됐다면, 변수 중요도를 부수적으로 확인하라는 것이지 목적이 아니다.
💡 Decision Tree는 첫 분석에서 정보이득을 가장 크게 얻을 수 있는 feature(독립변수)를 찾는 것이 중요.
💡 max_depth = 5로 하는 튜닝은 train으로만 계속 해보는 것.
따라서 우리는 계속 튜닝하면 안됨. 우리는 test값이기 때문에
💡Linear Regression vs kNN vs Decision Tree
| Linear Regression (선형 회귀) |
- 회귀문제만 가능 - feature(독립변수)들이 많을수록 모델이 복잡해진다. - 적절한 독립변수를 넣는 것이 중요. - 정말 중요한 변수들에 가중치 |
| kNN | - 분류와 회귀 둘 다 가능 따라서 k값이 중요 - k값의 파라미터 값은 n-neighbors이다. 최적의 이웃의 개수 - 학습데이터가 100개일 때, k값이 100개이면 평균이 된다. k가 데이터 개수가 되면 평균이 되고 가장 단순한 모델이 된다. 따라서, k가 클수록 가장 단순한 모델이 된다. ( k가 1일 때(작을수록) 가장 복잡한 모델이다.) ( k값은 많아야 5 ~ 10 사이이다. 10도 너무 많음) |
| Decision Tree (결정 트리) |
- 분류와 회귀 둘 다 가능 - max_depth가 클수록 복잡해진다. 적절한 max_depth를 넣어주는 것이 중요. |
- 모델이 복잡하다는 것은 과대적합 가능성이 높다는 것.
너무 학습에 치중한 나머지 평가데이터의 성능이 안좋아진다.
📕 Logistic Regression(로지스틱 회귀)
-로지스틱 회귀는 선형 회귀 방식을 '분류'에 적용한 알고리즘이다.
ex)종양 데이터를 근거로 종양인지(Y=1) 아닌지(N=0)를 판단하는 문제에 적용할 수 있다.
- 시그모이드(sigmoid) 함수라고도 부름
시그모이드 함수는 X 값이 아무리 커지거나 작아져도 1이나 0 값 만을 반환하는 함수이다.
(-∞, ∞) 범위를 갖는 선형 선형 판별식 결과로 (0,1)범위의 확률 값을 얻게 됨.
- 확률 값 0.5를 기준으로 이진 분류를 수행할 수 있게 됨.
- 학습을 통해 선형 회귀선을 찾는 것이 아니라 로지스틱 함수에 의해 반환되는 값을 확률로 간주하여 그 확률에 따라 분류를 결정함.
💡 로지스틱 회귀는 선형 회귀 방식을 기반으로 하되 시그모이드 함수를 이용하여 '분류'를 수행하는 회귀이다. 지도학습의 대장인 '회귀'와 '분류'가 합쳐진 로직이다.
🌟하지만 잊지 말자 로지스틱 회귀에서 '회귀'는 도구이고 '분류'가 목적이라는 점을!
😅 [0,1]은 리스트가 아니라 포함.
(0,1)은 튜플이 아니라 미포함.
💻 Logistic Regression분류문제(ML03_04_로시즈틱회귀(Iris))
📌 모델링
# 1단계: 불러오기
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, classification_report
# mean_absolute_error,r2_score가 아님을 기억하자
# 2단계: 선언하기
model= LogisticRegression()
# 3단계: 학습하기
model.fit(x_train,y_train)
# 4단계: 예측하기
y_pred = model.predict(x_test)
# 5단계 평가하기
print(confusion_matrix(y_test,y_pred))
print(classification_report(y_test,y_pred))
💡 # 1단계: 불러오기
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, classification_report
# mean_absolute_error,r2_score가 아님을 기억하자
잠깐❗) 분류 => from sklearn.metrics import confusion_matrix, classification_report
회귀 => from sklearn.metrics import mean_absolute_error, r2_score
📌 첫번째 품종(setosa)의 확률값을 시각화하기
# 확률값 얻기
p=model.predict_proba(x_test)
p[:5].round(2)
# 어떤 품종의 확률값인지 확인하기
y_pred[:10]
p=model.predict_proba(x_test) # 확률값 얻기
plt.plot( np.sort(p[:,0]) ) # 정렬해서 시각화
plt.show()
'KT AIVLE School 3기 > 머신러닝' 카테고리의 다른 글
| KT Ailvle DX트랙 29일차 (0) | 2023.03.14 |
|---|---|
| KT Aivle DX 트랙 27일차 (0) | 2023.03.11 |
| KT Avile DX트랙 25일차 (0) | 2023.03.08 |
| KT Avile DX트랙 24일차 (0) | 2023.03.07 |
| KT Aivle DX트랙 23일차 (0) | 2023.03.06 |