신호처리 AI 프로젝트를 시작하면서 프로젝트 초기 데이터 분석을 하던 중 레퍼런스 중 기본연구보고서에서 결정트리를 시각화 한 사진을 보고 좋은 방법이라는 생각이 들어서 머신러닝으로 데이터를 분석하기 시작했다

 

 

1. DecisionTreeClassifier plot_tree 방법

처음에는 기본연구보고서와 같은방법으로 결정트리로 시각화 해보았으나 아래의 사진처럼 분석하던 데이터는 아래의 사진처럼 단순 트리 구조만으로 시각화 하기에는 좋지 않아보였고 이보다는 차트나 군집으로 시각화 하는것이 맞겠다는 생각이 들어서 XAI 방법에 대해 찾아보던 중 XGBoost로 시각화하는 방법을 찾게 됐다.

 

 

2. XGBoost - importance feature, Decision Boundary

XGBoost의 XGBClassifier의 gbtree booster를 사용해 트리 모델을 사용하면 트리 결과를 사용하여 아래 사진과 같이 시각화가 가능했다. feature importance의 결과를 바탕으로 값이 높은 feature 2개를 사용해서 시각화 하도록 만들었다. 확실히 한눈에 잘 보여서 이후 데이터 수집에서의 문제점을 찾아 ETL 프로그램을 수정했다.

 

 

3. 마무리

시각화로 인한 문제점 파악의 힘은 굉장했고 바로 핵심이 파악되어서 피쳐 엔지니어링 + 데이터 수집 관점 변경 으로 원하는 결과를 찾아냈다 피쳐 엔지니어링을 통해 찾아낸 핵심 데이터로 만든 오른쪽의 한줄로 구분되는 분류 모델은 매우 정확한 데이터 분석이였다 

 

프로젝트 초기 가능성 검사였고 분류 모델 AI인 점 + 시각화의 시너지가 잘맞아서 좋은 효과를 낸것 같다

이후 프로젝트에서 회귀 모델 분석에서도 XAI 방식을 적용해보면 좋을것 같다

 

 

4. Code

XGB 사용되는 부분의 기본 코드입니다

# 훈련/테스트 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.7)#, random_state=1)

# XGBoost 모델 학습
xg_reg = XGBClassifier(
    booster='gbtree', 
    max_depth=20, 
    objective='binary:logistic', 
    eval_metric='logloss',
    verbosity=0,
    n_estimators = 100,
    device='cuda',
    validate_parameters = True)
xg_reg.fit(X_train, y_train)

pred = xg_reg.predict_proba(X_test)
pred_t = pred[:, -1]
fpr, tpr, _ = roc_curve(y_test.values, pred_t)

print('XGBoost AUC:', auc(fpr, tpr))

# 피처 중요도 시각화
plt.figure(figsize=(10, 6))
plot_importance(xg_reg, importance_type='weight', max_num_features=10, height=0.5)
plt.show()

# XGB 경계 시각화
xg_importantces_param_count = 2

xg_importances = xg_reg.feature_importances_
xg_indices = np.argsort(importances)[::-1]
xg_importances_param = X.columns[xg_indices[:xg_importantces_param_count]]

X_subset = X_train[[xg_importances_param[i] for i in range(xg_importantces_param_count)]]
xg_subset_reg = XGBClassifier(
    booster='gbtree', 
    max_depth=20, 
    objective='binary:logistic', 
    eval_metric='rmse',
    verbosity=0,
    n_estimators = 100,
    device='cuda',
    validate_parameters = True)
xg_subset_reg.fit(X_subset, y_train)

x_min, x_max = X_subset[xg_importances_param[0]].min() - 1, X_subset[xg_importances_param[0]].max() + 1
y_min, y_max = X_subset[xg_importances_param[1]].min() - 1, X_subset[xg_importances_param[1]].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),
                     np.arange(y_min, y_max, 0.01))
Z = xg_subset_reg.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

plt.figure(figsize=(10, 6))
plt.contourf(xx, yy, Z, alpha=0.4, cmap='viridis')
sns.scatterplot(x=X_train[xg_importances_param[0]], y=X_train[xg_importances_param[1]], hue=y_train, palette='viridis', edgecolor='k')
plt.title(f'Decision Boundary ({xg_importances_param[0]} vs {xg_importances_param[1]})')
plt.xlabel(f'{xg_importances_param[0]}')
plt.ylabel(f'{xg_importances_param[1]}')
plt.show()

+ Recent posts