import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
이항분류
- 합격/ 불합격 판정
- 3과목의 평균 60점 이상 합격 (단, 과락 40점 미만은 불합격)
1. 함수 생성
1-1) 사용할 lib import
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
1-2) 데이터 생성
# sample로 사용할 DataSet을 생성하는 함수 작성
# X: 국어, 영어, 수학 점수
# Y: 합격여부 (X의 평균 60이상, 과락 40점 미만)
# seedno : 랜덤 수 생성 규칙
# size : 랜덤 수 생성 행의 수
# step=0 (균형), step=다른수 (불균형) / step=0 균형 다른 수=불균형
def make_sample(seedno, size, step=0):
colnames=['국어', '영어', '수학']
np.random.seed(seedno) #랜덤수를 발생
A = np.random.randint(0, 101, (size, 3)) #0~100사이 수 (행, 열)
df = pd.DataFrame(A, columns=colnames)
df['합격여부'] = (df.mean(axis=1) >= 60) & (df.min(axis=1)>=40) #가로로 (행별 합계) mean
df #이렇게만 하면 점수가 너무 낮아서 다 False가 됨 (0~100 비율이 무작위라서)
# 출력결과 (size=20000)
#False 16340 / True 3660 --> 불균형 데이터
if step == 0:
F, T = df['합격여부'].value_counts()
B = np.random.randint(60,101,(F-T, 3)) #B=합격자 / f-t 수만큼의 행+3과목
df2 = pd.DataFrame(B, columns=colnames)
df2['합격여부'] = True
df = pd.concat([df, df2])
df['합격여부'].value_counts()
df.index = pd.RangeIndex(len(df)) #df의 index 변경
#합격 여부 TF이 아닌 01로 변경
df['합격여부'] = df['합격여부'].replace({True:1, False:0}) #합격1 불합격0
return df
1-3) 모델 학습 및 성능 평가 함수 생성 (순서 중요!)
1) X, Y 데이터 분리
2) 학습, 평가 데이터로 분리 (train_test_split)
3) 분리된 데이터의 shape 출력
4) 학습 모델 선택, 학습
5) 성능 평가
model, data가 파라미터인 ModelTrain 함수 생성
def ModelTrain(model, data):
# 1) X, Y 데이터 분리
Y = data['합격여부']
X = data.drop(columns=['합격여부']) #data에서 합격여부 컬럼을 제외한 모든 컬럼
# 2) 학습, 평가 데이터로 분리
x_train, x_test, y_train, y_test = train_test_split(X, Y,
test_size=0.2,
stratify=Y,
random_state=0)
# 3) 분리된 데이터의 shape 출력
print([ x.shape for x in [x_train, x_test, y_train, y_test]])
#print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)
# 4) 학습 모델 선택, 학습
#model = LogisticRegression(max_iter=1000) < 반복수행=1000
model.fit(x_train, y_train)
# 5) 성능 평가 - 정확도로 평가할 것 (Accuracy)
#train, test 성능을 모두 확인해야 과대적합 여부 확인
print('train 성능 : ', model.score(x_train, y_train))
print('test 성능 : ', model.score(x_test, y_test))
return model
2. 데이터의 중요성 알아보기
model1: 데이터 양 多 균형 데이터
for no in [1234, 1225, 1245] :
model1 = LogisticRegression(max_iter=1000) #max_iter=hyperparameter
data = make_sample(seedno=no, size=20000) #seedno=난수발생에 사용되는 숫자, size=행
ModelTrain(model1, data)
model2: 데이터 양 多 불균형 데이터
for no in [1234, 1225, 1245] :
model2 = LogisticRegression(max_iter=1000)
data = make_sample(seedno=no, size=32000, step=1) # step=1 불균형
ModelTrain(model2, data)
model3: 데이터 양 小 균형 데이터
for no in [1234, 1225, 1245] :
model3 = LogisticRegression(max_iter=1000)
data = make_sample(seedno=no, size=40)
ModelTrain(model3, data)
model4: 데이터 양 小 불균형 데이터
for no in [1234, 1225, 1245] :
model4 = LogisticRegression(max_iter=1000)
data = make_sample(no, 60, step=1)
ModelTrain(model4, data)
3. 파생변수
합격/ 불합격 여부를 결정하는 평균, 과락에 관련된 파생변수를 추가
(but 파생변수를 추가한다고 모든 데이터의 성능 향상에 도움이 되는건 아니다)
# 데이터 생성
data = make_sample(seedno=1245, size=20000)
# 파생변수 생성/ 추가
data['평균'] = data[['국어', '영어', '수학']].mean(axis=1) # 행
data['최저'] = data[['국어', '영어', '수학']].min(axis=1)
# 평균, 최저 파생변수 생성
for no in [1234, 1225, 1245] :
model5 = LogisticRegression(max_iter=1000)
data = make_sample(seedno=no, size=20000)
data['평균'] = data[['국어', '영어', '수학']].mean(axis=1)
data['최저'] = data[['국어', '영어', '수학']].min(axis=1)
ModelTrain(model5, data)
# 모든 값을 사용한 예측 결과
def make_all() :
colnames = ['국어','영어','수학']
data = [[kor, eng, mat] for kor in range(101) for eng in range(101) for mat in range(101)]
data = pd.DataFrame(data, columns=colanmes)
data['평균'] = data[['국어','영어','수학']].mean(axis=1)
data['최저'] = data[['국어', '영어', '수학']].min(axis=1)
data['합격여부'] = (data['평균'] >= 60) & (data['최저'] >= 40)
data['합격여부'] = data['합격여부'].replace({True:1, Fales:0}) #합격:1 불합격:0
return data
data = make_all()
X1 = data.iloc[:, :3]
X2 = data.drop(columns=['합격여부'])
Y = data['합격여부']
print(Y.value_counts())
for x in model1, model2, model3, model4:
print(x.score(X1, Y))
print(model5.score(X2, Y))
# 1-데이터多균형 2-데이터多불균형 3-데이터小균형 4-데이터小불균형 5-파생변수추가
4. 스케일러
for no in [1234, 1225, 1245] :
model6 = LogisticRegression(max_iter=1000)
data = make_sample(seedno=no, size=20000)
data['국어'] *= 500
data['수학'] *= 1000
ModelTrain(model6, data)
# StandardScaler 사용하여 정규 분포 만들기
from sklearn.preprocessing import StandardScaler
for no in [1234, 1225, 1245]:
model7 = LogisticRegression(max_iter=1000)
data = make_sample(seedno=no, size=20000)
data['국어'] *= 500
data['수학'] *= 1000
X = data[['국어', '영어', '수학']]
Y = data['합격여부']
scaledX = StandardScaler().fit_transform(X)
scaledX = pd.DataFrame(scaledX, columns=['국어', '영어', '수학'])
data = pd.concat([scaledX, Y], axis=1)
ModelTrain(model7, data)
# 수가 차이가 클 경우 Scaler를 하는 것이 도움이 될 수도 있다
5. 다양한 모델의 사용
#선형모델
from sklearn.linear_model import LogisticRegression
#근접이웃
from sklearn.neighbors import KNeighborsClassifier
#트리
from sklearn.tree import DecisionTreeClassifier
#앙상블
from sklearn.ensemble import RandomForestClassifier
from xgboost import XGBClassifier
데이터 생성
# 학습용 데이터
data = make_sample(seedno=1234, size=20000)
# 평가용 데이터
all = make_all() #모든 케이스
X = all.iloc[:, :3]
Y = all['합격여부']
분류 모델
A) LogisticRegression
- 독립 변수의 선형 결합을 이용하여 사건의 발생 가능성을 예측하는데 사용되는 통계 기법
- 반복하면서 기울기 값 갱신, 기울기 미분값이 0이 되는 지점을 찾음
- max_iter ,tol (자주 사용되는 값) 등을 변경 -> 성능 개선 가능
- max_iter = 반복횟수 (학습이 부족할 시 반복횟수 up/ 과대적합 시 반복횟수 down)
- tol = 허용오차, 반복을 중단하는 조건으로 사용
- panalty = panalty 종류
- C = panalty 세기
- LinearRegression : y가 0보다 작거나 1보다 큰 값도 존재
- ex) y=0 불합격 y=1 합격이라고 한다면 LinearRegression 모델 사용 시 y<0 | y>1 나올 수도 있기 때문에 부적합
- LogisticRegression : y가 0과 1사이의 확률값
- ex) 0과 1사이의 값이 나오기 때문에 확률값을 구하고, 그 확률이 두 가지 값이라면 0.5보다 컸을 때 원하는 결과를 구할 수 있음 (분류모델- 확률값을 가지고 있고, 그 확률이 가장 큰 값을 찾는 것임)
#LogisticRegression 모델 사용 시 성능 평가
model_lr = LogisticRegression(max_iter=1000)
ModelTrain(model_lr, data)
print(model_lr.score(X, Y)
#model_lr = LogisticRegression(max_iter=1000, C=0.3, tol=0.01)
#위처럼 C와 tol값을 줬을 때 변화가 크진 않음 -> 무조건 개선되거나 변화되는 것은 아니라는 것 알기
B) KNeighborsClassifier
- k개의 근접 이웃을 확인하여 클래스를 선택함
- n_neighbors를 변경 -> 성능 개선 가능 (확인할 근접 이웃 개수)
- 이웃 값을 구해야하기 때문에 다른 모델보다 조금 느림
#knn 모델 사용 시 성능 평가
model_knn = KNeighborsClassifier(n_neighbors = 5)
ModelTrain(model_knn, data)
print(model_knn.score(X, Y))
#n_neighbors를 범주로 주고 싶을 때 (ex-3~9)
for k in range(3, 10) :
model_knn = KNeighborsClassifier(n_neighbors=k)
ModelTrain(model_knn, data)
print(f'k={k}, {model_knn.score(X, Y)}')
따로 설정한 값이 없는데도 LogisticRegression보다 좋게 나옴
-> 각 유형별로 알맞는 모델이 달라서 많은 모델을 써보고 제일 성능값이 좋은 모델을 택하는 게 좋음
선택해야 하는 모델
1) train 성능과 test 성능의 차이값이 적은 것
2) 두 성능 값이 모두 높은 것
C) DecisionTreeClassfier
- overfitting 경향이 있음
- max_depth를 줄이는 방법으로 overfitting 해결 가능
#DecisionTreeClassifier 모델 사용 시 성능 평가
model_dc1 = DecisionTreeClassfier()
ModelTrain(model_dc1, data)
print(model_dc1.score(X, Y))
depth 구하기
.get_depth()
#depth가 어디까지 쓰였는지 확인
model_dc1.get_depth() #12 출력됨
#depth=6으로 줄여보기
#train-test 성능 차가 클 때 depth를 줄이는 방법으로 overfitting을 줄일 수 있다
model_dc2 = DecisionTreeClassifier(max_depth=6)
ModelTrain(model_dc2, data)
print(model_dc2.score(X, Y))
# depth=3으로 줄이기
model_dc3 = DecisionTreeClassifier(max_depth=3)
ModelTrain(model_dc3, data)
print(model_dc3.score(X, Y))
D) RandomForestClassfier
- DecisionTreeClassifier를 100개 사용하는 앙상블 모델 (트리 기반)
- n_estimators 의 개수를 늘리거나, max_depth를 조절하여 성능 조절 가능
model_rf1 = RandomForestClassifier()
ModelTrain(model_rf1, data)
print(model_rf1.score(X, Y))
#estimators 늘리기 (기본 100)
model_rf2 = RandomForestClassifier(n_estimators=500)
ModelTrain(model_rf2, data)
print(model_rf2.score(X, Y))
E) XGBClassifier
from xgboost import XGBClassifier
model_xgb1 = XGBClassifier()
ModelTrain(model_xgb1, data)
print(model_rf1.score(X, Y))
#n_estimator 높이고, max_dapth=5로 줄이기
model_xgb2 = XGBClassifier(n_estimator=500, max_depth=5)
ModelTrain(model_xgb2, data)
print(model_xgb2.score(X, Y))
성능 평가 (rf, xgb)
성능이 좋았던 RandomForestClassfier을 이용해 모델 생성
data = make_sample(seedno=1234, size=50000)
model_rf = RandomForestClassifier(n_estimators=500)
ModelTrain(model_rf, data)
성능이 좋았던 XGBClassifier을 이용해 모델 생성
data = make_sample(seedno=1234, size=50000)
model_xgb = XGBClassifier(n_estimators=500)
ModelTrain(model_xgb, data)
오분류표 생성
- sklearn.metrics.confusion_matrix(y_true, y_pred, *, labels=None, sample_weight=None, normalize=None)
- y_true: 실제값
- y_pred: 예측값
1) rf 를 이용해 각 종류별 정확도 확인
from sklearn.metrics import confusion_matrix
label=['불합격', '합격']
print(model_rf.score(X, Y))
y_pred = model_rf.predict(X)
a = confusion_matrix(Y, y_pred)
# a만으로는 컬럼, 인덱스로 보이지 않아서 DataFrame으로 변환 후 보여줌
b = pd.DataFrame(a, columns=label, index=label)
b
2) xgb를 이용해 각 종류별 정확도 확인
from sklearn.metrics import confusion_matrix
label = ['불합격', '합격']
print(model_xgb.score(X, Y))
y_pred = model_xgb.predict(X)
a = confusion_matrix(Y, y_pred)
b = pd.DataFrame(a, columns=label, index=label)
b
3) 합격일 확률 구하기 (다른 데이터 사용)
data = make_sample(seedno=1234, size=6)
x_test = data[['국어', '영어', '수학']]
y_test = data['합격여부']
print(y_test.to_numpy()) # 실제값
print(model_xgb.predict(x_test)) # 예측값
proba = model_xgb.predict_proba(x_test)
print(proba)
예측값 저장
# test데이터에서 '합격'일 확률에 대한 정보를 저장 후 출력
submission = pd.DataFrame()
submission['id'] = pd.RangeIndex(1, len(X) + 1) #일련번호
submission['prob'] = model_xgb.predict_proba(X)[:, 1] #1일 확률만 빼서 만듦
submission.to_csv('submission.csv', index=False) #파일명:submission, index 저장 X
--> id, proba :, 1 (2열까지) 저장
모델 학습 및 성능 평가 함수 생성
1) X, Y 데이터 분리
2) 학습, 평가 데이터로 분리 (train_test_split)
3) 분리된 데이터의 shape 출력
4) 학습 모델 선택, 학습
5) 성능 평가(정확도로 평가했음/ train, test 성능을 모두 확인해야 과대적합 여부 확인 가능)
성능 조절
+파생변수
+스케일러 (from sklearn.preprocessing import StandardScaler)
분류모델
1) LogisticRegression
from sklearn.linear_model import LogisticRegression
2) KNeighborsClassifier
from sklearn.neighbors import KNeighborsClassifier
3) DecisionTreeClassifier
from sklearn.tree import DecisionTreeClassifier
4) RandomForestClassifier
from sklearn.ensemble import RandomForestClassifier
5) XGBClassifier
from xgboost import XGBClassifier
'PYTHON > 빅데이터분석기사' 카테고리의 다른 글
ML_03 (classification s3-22~24 2회 기출/화물 정시 도착) (0) | 2023.11.14 |
---|---|
ML_03 (classification s3-16~21 작업형 2 예시/고객 성별 예측) (0) | 2023.11.14 |
ML_02 (Introduction s3-05~09 붓꽃 품종 예측 / sklearn lib) (0) | 2023.11.13 |
ML_01-1 (basic s3-03 자녀의 키 예측하기) (0) | 2023.11.10 |
ML_01 (basic s3-01~02) (0) | 2023.11.05 |