지난번에 작성했었던 불균형 데이터 연습 코드를 이어서 써보도록 하겠다.
[기록] 이상탐지(지도, 분류) - 불균형 데이터 연습(1) ( OverSampling, UnderSampling, Standardscaler, H2O autoML)
위 링크에서 이어집니다.
3. 코드 (이어서)
# 이전 게시글과 이어집니다.
# Run Automl
import h2o
from h2o.automl import H2OAutoML
h2o.init()# Start h2o server
train_h2o = h2o.H2OFrame(X_train_df) # train_data는 pandas DataFrame
test_h2o = h2o.H2OFrame(X_test_df) # test_data는 pandas DataFrame
total_h2o = h2o.H2OFrame(X_total_df) # 표준화된 total + y
target_column = 'label' # target
# change y to object type
train_h2o['label'] = train_h2o['label'].asfactor()
test_h2o['label'] = test_h2o['label'].asfactor()
total_h2o['label'] = total_h2o['label'].asfactor()
train for 1 hour
aml = H2OAutoML(max_models=5, max_runtime_secs=3000, seed=42)
aml.train(y=target_column, training_frame=train_h2o) # train
lb = aml.leaderboard
print(lb)
[코드설명]
h2o.init() : h2o서버를 시작
H2OFrame : h2o모델을 돌릴 수 있도록 변환
asfactor() : 분류 모델이기 때문에 0, 1을 object 형식으로? 변환
H2OAutoML : AutoML실행.
max_models : 최대 모델 개수
max_runtime_secs : 최대 실행 시간
leaderboard : 성능 좋은 모델 순으로 정렬
Automl 모델을 통해 예측
# 모든 모델 ID 리스트 가져오기
model_ids = lb['model_id'].as_data_frame().values.flatten().tolist()
# sampling유형에 따라 만든 folderpath 이용
base_folder = "/yourPath" + folderpath.split('.')[1] + "models/"
print("base_foler:", base_folder)
# 각 모델을 저장하고 예측 수행
for model_id in model_ids:
model = h2o.get_model(model_id)
model_path = os.path.join(base_folder, model_id)
print("model_path: ", model_path)
model_path = h2o.save_model(model=model, path = model_path)
print(f"Model {model.model_id} saved to {model_path}")
######## Test(valid) predict ########
predictions = model.predict(test_h2o)
predictions_df = predictions.as_data_frame()
result_test_df = pd.DataFrame()
result_test_df['label'] = y_test.values
result_test_df['predict_label'] = predictions_df['predict']
result_test_df['predicted_as_0'] = predictions_df['p0']
result_test_df['predicted_as_1'] = predictions_df['p1']
labels = result_test_df['label']
predictions = result_test_df['predict_label']
conf_matrix = confusion_matrix(labels, predictions)
# 결과 출력
print("confution Matrix In Test(Valid):")
print(conf_matrix)
tn, fp, fn, tp = conf_matrix.ravel()
print("TN:", tn)
print("FP:", fp)
print("FN:", fn)
print("TP:", tp)
print("Accuracy:", (tp + tn) / (tp + tn + fp + fn)) # 정확도
print("Precision:", tp / (tp + fp) if (tp + fp) > 0 else 0) # 정밀도
print("Recall:", tp / (tp + fn) if (tp + fn) > 0 else 0) # 재현율
print("F1 Score:", 2 * (tp / (tp + fp) if (tp + fp) > 0 else 0) * (tp / (tp + fn) if (tp + fn) > 0 else 0) / ((tp / (tp + fp) if (tp + fp) > 0 else 0) + (tp / (tp + fn) if (tp + fn) > 0 else 0)) if (tp / (tp + fp) if (tp + fp) > 0 else 0) + (tp / (tp + fn) if (tp + fn) > 0 else 0) > 0 else 0) # F1 점수
# save result to csv
result_test_df.to_csv(f"{folderpath}valid_results/{model.model_id}.csv", index=False)
print(f"Validate Result for model {model.model_id} save to {folderpath}/valid_results.")
######## Total(train + valid) predict ########
total_predictions = model.predict(total_h2o)
total_predictions_df = total_predictions.as_data_frame()
data_df_tm.reset_index(drop=True, inplace=True)
data_df_tm['predict'] = total_predictions_df['predict']
data_df_tm['predicted_as_0'] = total_predictions_df['p0']
data_df_tm['predicted_as_1'] = total_predictions_df['p1']
labels = data_df_tm['label']
predictions = data_df_tm['predict']
conf_matrix = confusion_matrix(labels, predictions)
# 결과 출력
print("confution Matrix In Total:")
print(conf_matrix)
tn, fp, fn, tp = conf_matrix.ravel()
print("TN:", tn)
print("FP:", fp)
print("FN:", fn)
print("TP:", tp)
print("Accuracy:", (tp + tn) / (tp + tn + fp + fn)) # 정확도
print("Precision:", tp / (tp + fp) if (tp + fp) > 0 else 0) # 정밀도
print("Recall:", tp / (tp + fn) if (tp + fn) > 0 else 0) # 재현율
print("F1 Score:", 2 * (tp / (tp + fp) if (tp + fp) > 0 else 0) * (tp / (tp + fn) if (tp + fn) > 0 else 0) / ((tp / (tp + fp) if (tp + fp) > 0 else 0) + (tp / (tp + fn) if (tp + fn) > 0 else 0)) if (tp / (tp + fp) if (tp + fp) > 0 else 0) + (tp / (tp + fn) if (tp + fn) > 0 else 0) > 0 else 0) # F1 점수
# save result to csv
data_df_tm.to_csv(f"{folderpath}total_results/{model.model_id}.csv", index=False)
print(f"Total Result for model {model.model_id} saved to {folderpath}/total_results.")
# print leaderboard
print(lb)
# save leaderboard
lb_df = lb.as_data_frame()
lb_df.to_csv(f"{folderpath}/h2o_classifier_sampling-{args.sampling}_leaderboard_results.txt", index=False)
[코드설명]
model_ids : 리더보드에 등록된 모델들의 model id 가져오기
h2o.get_model : model id를 이용하여 모델 정보 가져오기
h2o.save_model : 모델 정보를 저장
predictions : 학습된 모델을 이용하여 예측값 도출
predictions_df['predict'] : 분류 결과 (0, 1 과 같이 라벨링 된 결과)
predictions_df['p0'] : 0으로 예측한 확률
predictions_df['p1'] : 1으로 예측한 확률
** predictions_df['p0']가 0.5 이상이면 predictions_df['predict']가 0으로 분류되고
predictions_df['p1']가 0.5 이상이면 predictions_df['predict']가 1으로 분류된다.
conf_matrix : 실제데이터와 예측 라벨링 결과를 함께 넣어 confusion matrix를 만듦
conf_matrix.ravel() : tn, fp, fn, tp 순서대로 값을 변수에 할당시킴
4. 주의사항
헷갈릴 수 있는 부분에 대해서 설명하도록 하겠다.
1. 정상 = 0 이상치 = 1인 데이터
불균형 데이터이기 때문에 0이 압도적으로 많고 1이 소량 있는 데이터인 상태이다.
본인의 데이터를 확실하게 확인해야 이해가 쉬우니 확실히 파악하고 넘어가야한다.
2. confusion matrix 에서 Positive, Negative
혼동행렬에서는 TN FP FN TP 이런식으로 표현하는데 여기서 Positive, Negative가 뭔지 헷갈릴 수 있다.(잠깐 이해했다가도 매일매일 헷갈렸다.)
Negative = 0 = 정상
Positive = 1 = 이상치
정상이 보통 긍정적인 느낌을 갖기때문에 정상이 positive처럼 느껴지지만 정상/이상치로 따지면 안되고 0과 1이 어떤것과 매칭되어있는지를 고려해야한다.
따라서 불균형 데이터에서 정상(0)이 굉장히 많은 상태이므로 TN >>>> TP이다.
만약 반대로 정상을 1, 이상치를 0으로 매칭시켰다면 반대로 해석하면 될것이다.
3. confusion matrix 순서
나같은 경우에는 confusion_matrix(실제, 예측) 순으로 넣었다.
그러면 결과는
[[TN, FP],
[FN, TP]]
이 순서로 나오게 된다.
예를들어 결과가
[[104890, 30],
[24, 40]]
이렇게 나왔다 가정해보자.
그러면 TN = 104890, FP = 30, FN = 24, TP = 40 인것이다.
그리고 confusion_matrix의 ravel()함수를 사용하면 이 순서대로 결과값을 추출해준다.
추출한 TN, FP, FN, TP를 이용해서 각종 평가지표를 계산할 수 있다.
다음 게시물에는 저장한 모델을 다시 불러오는 법에 대해서 올리도록 하겠다!!