04단계 · 2유형 — 예측과 제출
ROC AUC — 왜 확률을 제출하나
같은 모델의 AUC 를 확률로 잴 때와 라벨로 잴 때 비교해 차이를 확인한다.
먼저 알아볼게요
코드로 이동 ↓ROC AUC 는 "1 인 것에 더 높은 점수를 매겼는가" 를 재는 지표다. 0.5 는 찍은 것과 같고 1.0 이 완벽이다.
AUC 는 순위를 본다. 그래서 0/1 라벨 대신 확률이나 결정 점수처럼 순위를 담는 값을 넣어야 가진 정보를 다 쓴다. 라벨을 넣으면 순위 정보가 뭉개지는데, 완벽하게 맞힌 경우처럼 두 값이 같아지는 상황도 있으므로 "항상 더 낮다" 고 외우지는 않는다. 아래 이 데이터에서는 확실히 낮게 나온다.
roc_auc_score(정답, 확률) 순서다. 두 인자를 바꿔 넣으면 정답 자리에 확률이 들어가므로 보통은 ValueError: continuous format is not supported 로 멈춘다(이 실행 환경에서 확인). 조용히 틀리는 대신 오류로 알려 주는 드문 경우다.
발문이 "확률을 제출" 이라고 하면 predict_proba 를, "분류 결과를 제출" 이라고 하면 predict 를 쓴다. 채점 지표가 AUC 인데 라벨을 내면, 순위 정보가 빠진 답을 낸 것이 된다.
아래 과제에서 두 값을 나란히 보면 차이가 분명히 보인다. 이것이 이 수업의 전부다.
from sklearn.metrics import roc_auc_score
print(round(roc_auc_score([0, 0, 1, 1], [0.1, 0.4, 0.35, 0.8]), 4))
print(round(roc_auc_score([0, 0, 1, 1], [0, 0, 1, 1]), 4))AUC 는 순위를 보는 지표다. 라벨을 넣으면 순위 정보가 사라진다 — 이 데이터에서는 0.7118 이 0.6196 으로 떨어졌다.
앞 수업과 같은 방법으로 모델을 학습시킨 뒤 ① 확률로 잰 AUC(소수 4) ② 라벨로 잰 AUC(소수 4) ③ 확률 쪽이 더 큰지(True/False)를 출력하세요.
제공 파일 1개 · 내용 보기
파일은 준비되어 있어요. 코드에서 이름으로 불러오세요.
고객ID,성별,요금제,가입개월,월요금,부가서비스,이탈 C1001,남,standard,22,44300,3,1 C1002,여,premium,1,62000,1,1 C1003,남,premium,45,64000,0,1 C1004,남,basic,10,32200,1,1 C1005,남,premium,5,69500,0,1 C1006,여,basic,56,29500,0,0 C1007,여,premium,48,62800,2,0 C1008,여,standard,5,56700,1,1 C1009,여,basic,49,30600,3,0 C1010,여,premium,52,74800,2,1 C1011,여,basic,19,32800,2,1 C1012,여,standard,18,42200,3,0 C1013,남,standard,37,47900,1,0 C1014,남,basic,1,30500,4,1 C1015,여,standard,52,43200,0,0 C1016,남,premium,31,75300,3,1 C1017,여,basic,22,29100,1,1 C1018,남,standard,39,48400,1,1 C1019,남,premium,35,82500,0,0 C1020,남,standard,19,42600,3,0 C1021,남,basic,22,27300,4,1 C1022,여,basic,38,27800,1,1 C1023,남,standard,5,54200,0,1 C1024,여,premium,36,77200,3,0 C1025,여,standard,14,46500,1,1 C1026,남,premium,15,64500,2,1 C1027,남,basic,45,28100,4,0 C1028,남,standard,49,40600,1,1 C1029,남,standard,59,50800,4,0 C1030,여,basic,16,27800,3,1 C1031,남,basic,36,24900,0,1 C1032,남,basic,17,30200,4,0 C1033,여,basic,36,29900,3,1 C1034,남,basic,36,23800,2,0 C1035,여,standard,9,50200,1,1 C1036,여,premium,45,60800,2,0 C1037,여,standard,37,42900,3,0 C1038,여,basic,37,24800,2,0 C1039,남,standard,42,46300,0,0 C1040,여,basic,34,28400,2,1 C1041,남,premium,11,84200,3,1 C1042,남,standard,9,57000,4,1 C1043,여,standard,11,43500,3,1 C1044,여,basic,42,29200,2,1 C1045,여,premium,10,66800,4,1 C1046,남,premium,56,62700,2,0 C1047,남,standard,19,44100,3,1 C1048,여,basic,14,33700,2,0 C1049,여,basic,44,28800,0,1 C1050,여,premium,32,69800,0,1 C1051,남,basic,52,24100,3,0 C1052,남,standard,48,35900,1,0 C1053,여,basic,41,26300,0,0 C1054,여,basic,36,25500,1,1 C1055,여,basic,7,29000,3,0 C1056,여,basic,34,32700,3,1 C1057,남,standard,42,48900,4,1 C1058,여,basic,32,25800,1,1 C1059,남,standard,56,50100,3,0 C1060,여,standard,28,41500,1,0 C1061,여,premium,47,73900,0,0 C1062,남,premium,4,53900,3,1 C1063,여,premium,4,72600,0,1 C1064,여,basic,42,29100,4,1 C1065,남,basic,59,29800,4,0 C1066,남,premium,28,75100,1,0 C1067,남,basic,27,27200,0,0 C1068,남,basic,60,30100,2,1 C1069,여,premium,4,67400,1,1 C1070,여,basic,4,34100,0,1 C1071,남,standard,42,40800,4,0 C1072,여,premium,53,72900,4,0 C1073,남,standard,36,37500,1,0 C1074,남,standard,44,49800,0,0 C1075,남,basic,5,29700,3,1 C1076,남,premium,1,75600,3,1 C1077,남,standard,44,40600,1,1 C1078,여,basic,7,23800,1,0 C1079,여,premium,47,66100,4,1 C1080,남,standard,32,41500,1,0 C1081,남,premium,37,78500,4,1 C1082,남,premium,52,68500,1,0 C1083,남,premium,51,61900,3,1 C1084,남,basic,38,30000,2,1 C1085,남,basic,12,30900,0,0 C1086,남,premium,25,74900,1,1 C1087,여,standard,40,47300,1,0 C1088,남,standard,6,41600,1,1 C1089,남,premium,57,64200,4,0 C1090,여,basic,42,28700,0,1 C1091,여,standard,27,37300,0,1 C1092,남,basic,27,25900,2,1 C1093,여,basic,41,27900,0,0 C1094,남,standard,60,44200,0,0 C1095,남,premium,12,67100,2,1 C1096,남,standard,46,45700,1,0 C1097,여,standard,23,48800,1,1 C1098,남,premium,57,75300,4,0 C1099,남,premium,13,53900,0,0 C1100,여,premium,29,61600,3,1 C1101,남,standard,2,47300,3,1 C1102,남,standard,10,55900,1,1 C1103,남,premium,3,71800,1,1 C1104,남,premium,53,70000,1,0 C1105,남,premium,32,71300,2,1 C1106,남,premium,9,66000,0,1 C1107,여,premium,30,66100,2,1 C1108,남,standard,43,53500,3,0 C1109,남,basic,26,29400,4,0 C1110,여,standard,21,48500,4,0 C1111,남,standard,51,42400,0,1 C1112,남,premium,21,74100,4,0 C1113,남,premium,56,56600,0,0 C1114,남,standard,46,45300,4,0 C1115,여,standard,48,42300,4,0 C1116,여,basic,35,24700,4,1 C1117,여,premium,22,42700,1,0 C1118,남,standard,9,39900,4,1 C1119,남,premium,36,73100,1,0 C1120,여,premium,38,73800,0,1 C1121,여,standard,13,49300,4,0 C1122,남,basic,48,30300,0,0 C1123,남,standard,16,43800,0,1 C1124,남,premium,15,74000,2,1 C1125,남,basic,25,30200,0,1 C1126,남,basic,44,33000,2,1 C1127,남,basic,56,21800,3,0 C1128,남,standard,48,38600,1,0 C1129,여,premium,15,68200,0,1 C1130,여,basic,28,27400,3,0 C1131,남,standard,54,40800,4,0 C1132,남,basic,45,26900,3,0 C1133,여,premium,21,66200,0,1 C1134,여,premium,39,58900,0,0 C1135,남,basic,43,29000,3,0 C1136,남,standard,9,48600,4,1 C1137,남,basic,28,30300,1,0 C1138,남,premium,30,78600,4,0 C1139,남,basic,18,23900,3,0 C1140,남,standard,46,40900,2,1 C1141,남,premium,6,70300,0,1 C1142,남,basic,46,29100,1,0 C1143,남,standard,18,41600,3,0 C1144,여,basic,53,27800,3,1 C1145,여,basic,7,25400,0,1 C1146,남,basic,27,28800,0,1 C1147,여,premium,51,64300,4,0 C1148,남,premium,25,53100,2,0 C1149,남,standard,54,43800,1,1 C1150,남,premium,40,57700,0,1 C1151,여,standard,24,42900,3,1 C1152,남,premium,21,63300,1,1 C1153,여,standard,44,34800,3,0 C1154,여,basic,29,27400,2,1 C1155,여,premium,38,61500,1,0 C1156,여,premium,48,62600,4,0 C1157,남,basic,27,26900,1,1 C1158,남,standard,20,38000,4,0 C1159,여,premium,22,63700,2,1 C1160,여,standard,20,42800,1,0
들여쓰기: Tab · 편집기에서 나가기: Esc 다음 Tab
실행 결과
실행하면 코드가 출력한 내용이 여기에 나타나요.
막혔을 때
풀이와 비교하기
내 코드와 한 줄씩 비교해 보세요. 풀이를 보는 것만으로 완료되지는 않아요.
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OrdinalEncoder
train = pd.read_csv("churn_train.csv")
X = train.drop(columns=["고객ID", "이탈"])
y = train["이탈"]
x_tr, x_va, y_tr, y_va = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
enc = OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=-1)
x_tr[["성별", "요금제"]] = enc.fit_transform(x_tr[["성별", "요금제"]])
x_va[["성별", "요금제"]] = enc.transform(x_va[["성별", "요금제"]])
model = RandomForestClassifier(n_estimators=100, random_state=42).fit(x_tr, y_tr)
proba = model.predict_proba(x_va)[:, 1]
label = model.predict(x_va)
auc_proba = roc_auc_score(y_va, proba)
auc_label = roc_auc_score(y_va, label)
print(round(auc_proba, 4))
print(round(auc_label, 4))
print(auc_proba > auc_label)