본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 7. · 49 Views
모델 해석 SHAP과 LIME 완벽 가이드
머신러닝 모델의 예측 결과를 해석하는 두 가지 핵심 기법인 SHAP과 LIME을 초급자도 이해할 수 있도록 실무 예제와 함께 설명합니다. 블랙박스 모델의 예측 근거를 명확히 파악하는 방법을 배웁니다.
목차
- 블랙박스_모델의_문제점
- SHAP_개념과_원리
- SHAP_시각화_활용법
- LIME_개념과_원리
- LIME_실전_활용
- SHAP과_LIME_비교
- Feature_Importance와의_차이
- 실무_프로젝트_적용
- 주의사항과_한계점
- 최신_트렌드와_발전
1. 블랙박스 모델의 문제점
김개발 씨는 데이터 분석팀에서 일하는 주니어 데이터 사이언티스트입니다. 어느 날 김개발 씨가 만든 대출 승인 예측 모델이 특정 고객의 대출을 거절했습니다.
고객이 "왜 거절되었나요?"라고 물었을 때, 김개발 씨는 아무 말도 할 수 없었습니다.
블랙박스 모델이란 입력과 출력은 알 수 있지만, 그 사이의 과정을 해석하기 어려운 모델을 말합니다. 마치 요리사가 재료를 넣고 맛있는 음식을 내놓지만, 정확히 어떤 과정을 거쳤는지 알 수 없는 것과 같습니다.
딥러닝, 랜덤 포레스트, XGBoost 같은 고성능 모델들이 대표적인 블랙박스 모델입니다.
다음 코드를 살펴봅시다.
# 블랙박스 모델의 예측 - 왜 이런 결과가 나왔는지 알 수 없음
from sklearn.ensemble import RandomForestClassifier
import numpy as np
# 대출 승인 모델 학습
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# 특정 고객의 대출 예측
customer_data = np.array([[35, 50000, 2, 680]]) # 나이, 소득, 부양가족, 신용점수
prediction = model.predict(customer_data)
# 결과: 거절(0) - 하지만 왜 거절인지 설명할 수 없음
print(f"예측 결과: {'승인' if prediction[0] == 1 else '거절'}")
김개발 씨는 입사 6개월 차 주니어 데이터 사이언티스트입니다. 회사에서 대출 승인 예측 모델을 개발하라는 미션을 받고, 열심히 공부하여 정확도 95%의 훌륭한 모델을 만들었습니다.
그런데 문제가 생겼습니다. 어느 날 고객센터에서 전화가 왔습니다.
"김개발 씨, 고객분이 왜 대출이 거절되었는지 설명해달라고 하시는데요." 김개발 씨는 당황했습니다. 모델이 거절이라고 했을 뿐, 왜 거절인지는 모델 자체도 설명해주지 않았기 때문입니다.
선배 박시니어 씨가 다가와 상황을 들었습니다. "아, 블랙박스 문제에 부딪힌 거군요.
우리가 사용하는 랜덤 포레스트나 딥러닝 모델은 성능은 뛰어나지만, 내부 작동 원리를 설명하기가 매우 어려워요." 그렇다면 블랙박스 모델이란 정확히 무엇일까요? 쉽게 비유하자면, 블랙박스 모델은 마치 천재 요리사와 같습니다.
재료를 주면 맛있는 요리를 뚝딱 만들어내지만, "이 맛이 어떻게 나온 거예요?"라고 물으면 "그냥 느낌대로 했어요"라고 대답하는 것과 같습니다. 결과는 훌륭하지만, 그 과정을 논리적으로 설명할 수 없는 것입니다.
이런 블랙박스 특성이 왜 문제가 될까요? 첫째, 규제 준수 문제가 있습니다.
금융, 의료, 법률 분야에서는 AI의 결정에 대해 반드시 설명 가능해야 합니다. 유럽의 GDPR은 자동화된 의사결정에 대해 설명을 요구할 권리를 보장합니다.
둘째, 신뢰 문제입니다. 의사가 "AI가 암이라고 했어요"라고만 말한다면, 환자가 그 진단을 신뢰할 수 있을까요?
왜 그런 진단이 나왔는지 설명할 수 있어야 신뢰가 생깁니다. 셋째, 디버깅의 어려움입니다.
모델이 이상한 예측을 할 때, 원인을 찾기가 매우 어렵습니다. 마치 고장 난 자동차를 수리해야 하는데, 엔진 뚜껑을 열 수 없는 것과 같습니다.
박시니어 씨가 말했습니다. "그래서 우리에게는 모델 해석 기법이 필요해요.
SHAP과 LIME이 대표적이죠. 이 도구들을 사용하면 블랙박스 모델도 왜 그런 결정을 내렸는지 설명할 수 있어요." 김개발 씨의 눈이 반짝였습니다.
"그런 방법이 있었군요!" 이제부터 우리는 블랙박스를 열어볼 수 있는 열쇠, SHAP과 LIME에 대해 자세히 알아보겠습니다.
실전 팁
💡 - 고성능 모델일수록 해석하기 어려운 경향이 있으니, 해석 가능성과 성능 사이의 균형을 고려하세요
- 규제가 강한 산업에서는 모델 해석 기법 적용이 필수입니다
2. SHAP 개념과 원리
김개발 씨는 박시니어 씨에게 SHAP에 대해 배우기 시작했습니다. "SHAP은 게임이론에서 온 거예요?"라고 놀라는 김개발 씨에게, 박시니어 씨는 피자 배달 이야기로 설명을 시작했습니다.
SHAP(SHapley Additive exPlanations)은 게임이론의 Shapley Value를 기반으로 각 특성이 예측에 얼마나 기여했는지 계산하는 기법입니다. 마치 팀 프로젝트에서 각 팀원의 기여도를 공정하게 나누는 것처럼, 모델의 예측 결과에 대한 각 특성의 기여도를 수학적으로 정확하게 분배합니다.
다음 코드를 살펴봅시다.
import shap
import xgboost as xgb
# 모델 학습
model = xgb.XGBClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# SHAP Explainer 생성
explainer = shap.TreeExplainer(model)
# 특정 샘플의 SHAP 값 계산
shap_values = explainer.shap_values(X_test)
# 첫 번째 샘플의 예측 설명
# 각 특성이 예측에 얼마나 기여했는지 시각화
shap.force_plot(explainer.expected_value, shap_values[0], X_test.iloc[0])
박시니어 씨가 화이트보드 앞에 섰습니다. "김개발 씨, 혹시 친구들이랑 피자를 시켜 먹고 돈을 나눠 낸 적 있어요?" 김개발 씨가 고개를 끄덕였습니다.
"네, 보통 N분의 1로 나누죠." "그런데 만약 한 친구는 피자 2조각만 먹고, 다른 친구는 5조각을 먹었다면요? 그래도 똑같이 나눠야 할까요?" 이것이 바로 Shapley Value의 핵심 아이디어입니다.
노벨 경제학상을 받은 Lloyd Shapley가 제안한 이 개념은, 협력 게임에서 각 참여자의 기여도를 공정하게 분배하는 방법입니다. SHAP은 이 Shapley Value를 머신러닝에 적용한 것입니다.
모델의 예측이라는 결과물에 대해, 각 특성(변수)이 얼마나 기여했는지를 계산합니다. 어떻게 계산할까요?
박시니어 씨가 예를 들어 설명했습니다. "대출 승인 모델에 소득, 나이, 신용점수 세 가지 특성이 있다고 해봐요.
소득의 기여도를 계산하려면, 소득이 있을 때와 없을 때의 차이를 봐야 해요. 그런데 나이만 있을 때 소득을 추가하는 것과, 나이와 신용점수가 모두 있을 때 소득을 추가하는 것은 효과가 다를 수 있어요." SHAP은 이런 모든 가능한 조합을 고려합니다.
소득만 있을 때, 소득과 나이가 있을 때, 세 가지 모두 있을 때 등 모든 경우의 수를 계산하여 평균을 냅니다. 이렇게 하면 수학적으로 공정한 기여도를 얻을 수 있습니다.
SHAP의 큰 장점은 세 가지 중요한 수학적 특성을 만족한다는 것입니다. 첫째, Local Accuracy(지역 정확성)입니다.
모든 특성의 SHAP 값을 더하면 실제 예측값과 기준값의 차이가 됩니다. 둘째, Missingness(결측성)입니다.
모델에 포함되지 않은 특성의 SHAP 값은 0입니다. 셋째, Consistency(일관성)입니다.
특성의 기여도가 증가하면 SHAP 값도 증가합니다. 김개발 씨가 질문했습니다.
"그런데 모든 조합을 다 계산하면 시간이 너무 오래 걸리지 않나요?" 박시니어 씨가 웃으며 대답했습니다. "좋은 질문이에요!
특성이 20개만 되어도 조합의 수가 100만 개가 넘어요. 그래서 SHAP 라이브러리는 모델 유형에 따라 최적화된 알고리즘을 제공해요.
TreeExplainer는 트리 기반 모델에 특화되어 있고, DeepExplainer는 딥러닝 모델에 사용해요." 실제 코드에서 TreeExplainer를 사용하면 XGBoost, LightGBM, Random Forest 같은 트리 기반 모델을 빠르게 해석할 수 있습니다. force_plot을 통해 각 특성이 예측을 높이는 방향(빨간색)인지 낮추는 방향(파란색)인지 직관적으로 확인할 수 있습니다.
"이제 고객에게 설명할 수 있겠네요!"라고 김개발 씨가 말했습니다. "신용점수가 낮아서 대출이 거절되었다, 이런 식으로요."
실전 팁
💡 - TreeExplainer는 트리 기반 모델에, KernelExplainer는 모든 모델에 사용 가능합니다
- SHAP 값의 합은 예측값과 기준값의 차이와 같습니다
3. SHAP 시각화 활용법
김개발 씨는 SHAP 값을 계산하는 방법을 배웠지만, 숫자만으로는 한눈에 이해하기 어려웠습니다. 박시니어 씨가 말했습니다.
"SHAP의 진가는 시각화에 있어요. 그래프 하나로 천 마디 말보다 더 많은 것을 전달할 수 있거든요."
SHAP 시각화는 모델 해석 결과를 직관적으로 보여주는 다양한 그래프를 제공합니다. summary plot은 전체 데이터셋에서 각 특성의 중요도를, force plot은 개별 예측의 이유를, dependence plot은 특성 간의 관계를 보여줍니다.
이러한 시각화를 통해 비전문가도 모델의 동작을 이해할 수 있습니다.
다음 코드를 살펴봅시다.
import shap
import matplotlib.pyplot as plt
# 전체 데이터셋의 SHAP 값 계산
shap_values = explainer.shap_values(X_test)
# 1. Summary Plot - 전체 특성 중요도 시각화
shap.summary_plot(shap_values, X_test)
# 2. Bar Plot - 평균 절대 SHAP 값으로 중요도 순위
shap.summary_plot(shap_values, X_test, plot_type="bar")
# 3. Dependence Plot - 특정 특성과 예측의 관계
shap.dependence_plot("income", shap_values, X_test)
# 4. Waterfall Plot - 단일 예측 분해
shap.waterfall_plot(shap.Explanation(values=shap_values[0],
base_values=explainer.expected_value,
data=X_test.iloc[0]))
박시니어 씨가 노트북 화면을 보여주며 설명을 시작했습니다. "SHAP이 강력한 이유 중 하나는 바로 이 시각화 기능이에요.
숫자만 보면 감이 안 오는데, 그래프로 보면 바로 이해가 되거든요." 첫 번째로 보여준 것은 Summary Plot이었습니다. 화면에는 특성들이 세로로 나열되어 있고, 각 특성 옆에 점들이 가로로 흩어져 있었습니다.
박시니어 씨가 설명했습니다. "이 그래프에서 위쪽에 있는 특성일수록 모델에 큰 영향을 미쳐요.
그리고 각 점은 하나의 데이터 샘플이에요." 점의 색상도 중요했습니다. 빨간색은 그 특성값이 높은 샘플, 파란색은 낮은 샘플을 나타냅니다.
"보세요, 신용점수 특성에서 빨간 점들이 오른쪽에 있죠? 이건 신용점수가 높을수록 대출 승인 확률이 높아진다는 뜻이에요." 김개발 씨가 감탄했습니다.
"한눈에 어떤 특성이 중요하고, 그 효과가 어떤 방향인지 알 수 있네요!" 두 번째는 Bar Plot이었습니다. 이 그래프는 더 단순했습니다.
각 특성의 평균 절대 SHAP 값을 막대그래프로 보여줍니다. "임원들한테 보고할 때는 이 그래프가 좋아요.
복잡한 설명 없이 어떤 특성이 가장 중요한지 바로 알 수 있거든요." 세 번째는 Dependence Plot이었습니다. 이 그래프는 특정 특성과 SHAP 값의 관계를 보여줍니다.
X축은 특성값, Y축은 해당 특성의 SHAP 값입니다. "소득에 대한 dependence plot을 보면 재미있는 패턴이 보여요."라고 박시니어 씨가 말했습니다.
"소득이 일정 수준까지는 SHAP 값이 급격히 증가하다가, 어느 정도 이상이 되면 완만해지는 게 보이죠? 이건 소득이 높을수록 대출 승인에 유리하지만, 일정 수준 이상에서는 효과가 줄어든다는 뜻이에요." 네 번째는 Waterfall Plot이었습니다.
이 그래프는 개별 예측을 분석할 때 사용합니다. 기준값에서 시작해서 각 특성이 예측값을 얼마나 올리고 내리는지 폭포처럼 보여줍니다.
"고객이 왜 거절되었는지 설명할 때 이 그래프를 보여주면 돼요."라고 박시니어 씨가 말했습니다. "보세요, 기준값이 0.5인데, 신용점수 때문에 0.2가 깎이고, 소득 때문에 0.1이 추가되고...
최종 예측값이 어떻게 나왔는지 한눈에 보이죠?" 김개발 씨가 고개를 끄덕였습니다. "이제 고객에게 시각적으로도 설명할 수 있겠네요.
그냥 숫자만 말하는 것보다 훨씬 설득력 있을 것 같아요." 박시니어 씨가 덧붙였습니다. "그리고 이런 시각화는 모델 디버깅에도 유용해요.
예상과 다른 패턴이 보이면 데이터나 모델에 문제가 있다는 신호일 수 있거든요."
실전 팁
💡 - summary plot은 전체 모델 이해에, waterfall plot은 개별 예측 설명에 적합합니다
- dependence plot에서 상호작용 효과도 확인할 수 있습니다
4. LIME 개념과 원리
김개발 씨가 SHAP을 열심히 공부하던 중, 박시니어 씨가 다른 기법도 있다고 말했습니다. "LIME이라고 들어봤어요?" 김개발 씨는 고개를 저었습니다.
"라임... 과일 말고 다른 게 있나요?"
LIME(Local Interpretable Model-agnostic Explanations)은 복잡한 모델의 개별 예측을 설명하기 위해 그 주변에서 단순한 모델을 학습시키는 기법입니다. 마치 복잡한 지형을 이해하기 위해 특정 지점 주변만 평평한 지도로 그려보는 것과 같습니다.
어떤 종류의 모델이든 적용할 수 있다는 것이 큰 장점입니다.
다음 코드를 살펴봅시다.
from lime import lime_tabular
import numpy as np
# LIME Explainer 생성
explainer = lime_tabular.LimeTabularExplainer(
training_data=X_train.values,
feature_names=X_train.columns.tolist(),
class_names=['거절', '승인'],
mode='classification'
)
# 특정 샘플에 대한 설명 생성
# 이 샘플 주변에서 간단한 선형 모델을 학습
explanation = explainer.explain_instance(
data_row=X_test.iloc[0].values,
predict_fn=model.predict_proba,
num_features=5 # 상위 5개 특성만 표시
)
# 결과 시각화
explanation.show_in_notebook()
박시니어 씨가 화이트보드에 복잡한 곡선을 그렸습니다. "이게 우리 모델의 결정 경계라고 생각해봐요.
엄청 복잡하죠? 이걸 전체적으로 설명하기는 어려워요." 그리고 곡선 위의 한 점에 작은 원을 그렸습니다.
"하지만 이 작은 영역만 보면 어떨까요? 곡선이라도 아주 작은 부분만 보면 거의 직선처럼 보이잖아요." 이것이 바로 LIME의 핵심 아이디어입니다.
LIME은 Local Interpretable Model-agnostic Explanations의 약자로, 세 가지 중요한 특성을 가지고 있습니다. 첫째, Local(지역적)입니다.
전체 모델을 설명하려 하지 않고, 특정 예측 하나만 설명합니다. 그 예측 주변의 작은 영역에서만 설명을 시도합니다.
둘째, Interpretable(해석 가능한)입니다. 복잡한 모델 대신 사람이 이해하기 쉬운 간단한 모델(선형 회귀 등)을 사용합니다.
셋째, Model-agnostic(모델 불가지론)입니다. 어떤 종류의 모델이든 상관없이 적용할 수 있습니다.
모델을 블랙박스로 취급하고, 입력과 출력만 사용합니다. LIME은 어떻게 작동할까요?
박시니어 씨가 단계별로 설명했습니다. "먼저 설명하고 싶은 샘플 주변에서 새로운 데이터를 만들어요.
원본 샘플을 조금씩 변형한 샘플들이죠." 김개발 씨가 고개를 갸웃했습니다. "어떻게 변형하는데요?" "예를 들어 소득이 50000이었다면, 49000, 51000, 45000 같은 값으로 바꿔보는 거예요.
이렇게 해서 수백 개의 새로운 샘플을 만들어요." 그 다음, 이 새로운 샘플들을 원래 모델에 넣어서 예측값을 얻습니다. 그리고 이 데이터로 간단한 선형 모델을 학습시킵니다.
"중요한 건, 원본 샘플에 가까운 샘플일수록 더 높은 가중치를 준다는 거예요."라고 박시니어 씨가 설명했습니다. "멀리 있는 샘플은 덜 중요하게 취급해요.
우리가 관심 있는 건 바로 그 지점 주변이니까요." 마지막으로 학습된 선형 모델의 계수가 각 특성의 중요도가 됩니다. 선형 모델은 해석하기 쉬우므로, 어떤 특성이 예측에 긍정적인지 부정적인지 바로 알 수 있습니다.
"SHAP이랑 뭐가 다른 거예요?"라고 김개발 씨가 물었습니다. 박시니어 씨가 대답했습니다.
"SHAP은 수학적으로 정확한 기여도를 계산해요. 반면 LIME은 근사치를 구하는 거예요.
대신 LIME은 어떤 모델이든 적용할 수 있고, 계산이 상대적으로 빨라요. 상황에 따라 적절한 도구를 선택하면 돼요."
실전 팁
💡 - LIME은 모델 종류에 상관없이 사용할 수 있어 범용성이 높습니다
- 샘플링 기반이므로 실행할 때마다 결과가 조금씩 달라질 수 있습니다
5. LIME 실전 활용
김개발 씨는 LIME의 개념을 이해했지만, 실제로 어떻게 활용하는지 궁금했습니다. 박시니어 씨가 실제 코드를 보여주며 말했습니다.
"LIME은 특히 텍스트나 이미지 분류 모델을 설명할 때 빛을 발해요."
LIME 실전 활용에서는 테이블 데이터뿐만 아니라 텍스트, 이미지 등 다양한 데이터 타입에 LIME을 적용하는 방법을 다룹니다. lime 라이브러리는 LimeTabularExplainer, LimeTextExplainer, LimeImageExplainer 등 데이터 타입별로 최적화된 클래스를 제공합니다.
다음 코드를 살펴봅시다.
from lime.lime_text import LimeTextExplainer
from sklearn.pipeline import Pipeline
# 텍스트 분류 모델 (스팸 필터 예시)
# 이미 학습된 파이프라인: 전처리 + 모델
text_pipeline = Pipeline([
('tfidf', TfidfVectorizer()),
('clf', LogisticRegression())
])
text_pipeline.fit(X_train_text, y_train_text)
# LIME Text Explainer 생성
text_explainer = LimeTextExplainer(class_names=['정상', '스팸'])
# 특정 이메일이 왜 스팸으로 분류되었는지 설명
email = "무료 경품 당첨! 지금 클릭하세요 100만원 즉시 지급"
explanation = text_explainer.explain_instance(
email,
text_pipeline.predict_proba,
num_features=6
)
# 어떤 단어가 스팸 판정에 기여했는지 확인
explanation.show_in_notebook()
박시니어 씨가 새로운 예제를 보여주었습니다. "이번에는 스팸 필터를 예로 들어볼게요.
어떤 이메일이 스팸으로 분류되었을 때, 왜 스팸인지 설명하고 싶다면 어떻게 해야 할까요?" 김개발 씨가 생각에 잠겼습니다. "음...
텍스트 데이터니까 테이블 데이터와는 다르게 처리해야 할 것 같은데요." "맞아요. 그래서 LIME은 LimeTextExplainer라는 별도의 클래스를 제공해요." 텍스트 LIME의 작동 방식은 흥미롭습니다.
원본 텍스트에서 단어들을 하나씩 제거하면서 새로운 샘플을 만듭니다. "무료 경품 당첨"에서 "무료"를 빼면 예측이 어떻게 바뀌는지, "경품"을 빼면 어떻게 되는지 확인하는 것입니다.
박시니어 씨가 결과 화면을 보여주었습니다. 화면에는 이메일 텍스트가 표시되어 있었고, 일부 단어들이 색깔로 하이라이트되어 있었습니다.
"보세요, '무료', '당첨', '클릭', '즉시'라는 단어들이 빨간색으로 표시되어 있죠? 이 단어들이 스팸 판정에 크게 기여했다는 뜻이에요." 김개발 씨가 감탄했습니다.
"정말 직관적이네요! 사용자에게 왜 이 메일이 스팸으로 분류되었는지 바로 설명할 수 있겠어요." 이미지 분류에도 LIME을 적용할 수 있습니다.
LimeImageExplainer는 이미지를 여러 영역(superpixel)으로 나누고, 각 영역을 가리면서 예측이 어떻게 바뀌는지 확인합니다. "예를 들어 고양이 사진을 분류하는 모델이 있다고 해봐요."라고 박시니어 씨가 말했습니다.
"LIME을 적용하면 모델이 고양이의 어떤 부분을 보고 '고양이'라고 판단했는지 알 수 있어요. 귀인지, 눈인지, 수염인지 말이에요." 실무에서 LIME이 특히 유용한 경우가 있습니다.
첫째, 모델이 예상과 다른 예측을 했을 때 원인을 파악할 수 있습니다. 둘째, 모델이 잘못된 근거로 올바른 답을 내는 경우를 발견할 수 있습니다.
예를 들어 늑대 사진을 분류하는 모델이 실제로는 배경의 눈(snow)을 보고 판단하고 있었다는 유명한 사례가 있습니다. 김개발 씨가 물었습니다.
"그런데 LIME은 매번 결과가 조금씩 다르다고 하셨잖아요. 그건 문제가 아닌가요?" 박시니어 씨가 고개를 끄덕였습니다.
"좋은 지적이에요. LIME은 샘플링 기반이라서 실행할 때마다 결과가 조금씩 달라질 수 있어요.
그래서 중요한 결정을 내릴 때는 여러 번 실행해서 일관된 패턴을 확인하는 게 좋아요."
실전 팁
💡 - 텍스트 LIME은 토큰(단어) 단위로 분석하므로 전처리 방식에 주의하세요
- 이미지 LIME은 superpixel 설정에 따라 결과가 달라질 수 있습니다
6. SHAP과 LIME 비교
김개발 씨는 SHAP과 LIME을 모두 배웠지만, 언제 어떤 것을 써야 할지 헷갈렸습니다. "둘 다 모델을 해석하는 건데, 차이점이 뭐예요?" 박시니어 씨가 친절하게 비교해주기 시작했습니다.
SHAP과 LIME 비교를 통해 각 기법의 장단점과 적합한 사용 상황을 이해할 수 있습니다. SHAP은 수학적 일관성과 전역적 해석이 강점이고, LIME은 모델 불가지론적 특성과 직관적인 설명이 강점입니다.
실무에서는 상황에 따라 두 기법을 적절히 조합하여 사용합니다.
다음 코드를 살펴봅시다.
import shap
from lime import lime_tabular
import pandas as pd
# 같은 샘플에 대해 SHAP과 LIME 비교
sample_idx = 0
sample = X_test.iloc[sample_idx]
# SHAP 분석
shap_explainer = shap.TreeExplainer(model)
shap_values = shap_explainer.shap_values(sample.values.reshape(1, -1))
# LIME 분석
lime_explainer = lime_tabular.LimeTabularExplainer(
X_train.values, feature_names=X_train.columns.tolist(),
class_names=['거절', '승인'], mode='classification'
)
lime_exp = lime_explainer.explain_instance(sample.values, model.predict_proba)
# 결과 비교 - 두 기법이 비슷한 특성을 중요하다고 판단하는지 확인
print("SHAP Top 3:", sorted(zip(X_train.columns, shap_values[0]),
key=lambda x: abs(x[1]), reverse=True)[:3])
print("LIME Top 3:", lime_exp.as_list()[:3])
박시니어 씨가 화이트보드를 둘로 나누고 각각 SHAP과 LIME이라고 적었습니다. "이제 두 기법을 본격적으로 비교해볼게요." 첫 번째 차이점은 이론적 기반입니다.
SHAP은 게임이론의 Shapley Value에 기반합니다. 수학적으로 증명된 공정한 분배 방식이죠.
반면 LIME은 국소적 선형 근사에 기반합니다. 복잡한 함수를 특정 점 주변에서 단순한 선형 함수로 근사하는 것입니다.
"SHAP이 더 정확한 건가요?"라고 김개발 씨가 물었습니다. "일반적으로 그렇다고 할 수 있어요."라고 박시니어 씨가 대답했습니다.
"SHAP은 수학적으로 일관된 해석을 보장하거든요. 하지만 LIME도 충분히 유용해요." 두 번째 차이점은 설명 범위입니다.
SHAP은 개별 예측(local)과 전체 모델(global) 모두를 설명할 수 있습니다. summary plot 같은 시각화로 전체 모델의 특성 중요도를 파악할 수 있죠.
반면 LIME은 기본적으로 개별 예측만 설명합니다. 각 예측을 하나씩 분석해야 합니다.
세 번째 차이점은 계산 속도입니다. SHAP, 특히 TreeExplainer는 트리 기반 모델에서 매우 빠릅니다.
하지만 KernelSHAP(범용 버전)은 상당히 느릴 수 있습니다. LIME은 대체로 빠른 편이지만, 샘플 수가 많아지면 느려질 수 있습니다.
네 번째 차이점은 모델 의존성입니다. LIME은 완전히 모델 불가지론적입니다.
모델을 블랙박스로 취급하고 predict 함수만 사용하므로, 어떤 모델이든 적용할 수 있습니다. SHAP도 KernelSHAP은 모델 불가지론적이지만, TreeExplainer나 DeepExplainer 같은 최적화 버전은 특정 모델에 종속됩니다.
다섯 번째 차이점은 일관성입니다. SHAP은 같은 데이터에 대해 항상 같은 결과를 줍니다(결정론적).
LIME은 샘플링 기반이라 실행할 때마다 결과가 조금씩 달라질 수 있습니다(확률론적). "그래서 언제 뭘 써야 해요?"라고 김개발 씨가 물었습니다.
박시니어 씨가 정리했습니다. "트리 기반 모델을 사용하고, 전체 모델과 개별 예측 모두를 분석하고 싶다면 SHAP을 추천해요.
특히 TreeExplainer를 쓰면 빠르고 정확하거든요." "반면에 어떤 모델이든 빠르게 개별 예측만 설명하고 싶다면 LIME이 좋아요. 특히 텍스트나 이미지 분류에서는 LIME의 시각화가 매우 직관적이에요." "그리고 실무에서는 둘 다 써보는 것도 좋아요.
두 기법이 비슷한 결과를 보여준다면 그 해석을 더 신뢰할 수 있거든요."
실전 팁
💡 - 가능하면 두 기법을 모두 적용해보고 결과를 비교하세요
- 규제가 엄격한 산업에서는 수학적 근거가 명확한 SHAP을 선호하는 경향이 있습니다
7. Feature Importance와의 차이
김개발 씨가 문득 궁금해졌습니다. "잠깐, 랜덤 포레스트에도 feature_importances_가 있잖아요.
그거랑 SHAP이 뭐가 다른 거예요?" 박시니어 씨가 중요한 차이점을 설명하기 시작했습니다.
전통적인 Feature Importance와 SHAP/LIME은 근본적으로 다른 관점에서 특성 중요도를 측정합니다. 전통적 방법은 전역적(global) 중요도만 제공하지만, SHAP과 LIME은 개별 예측에 대한 지역적(local) 설명을 제공합니다.
또한 SHAP은 방향성까지 알려주지만, 전통적 방법은 단순히 중요도 크기만 보여줍니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import RandomForestClassifier
import shap
import numpy as np
# 랜덤 포레스트 학습
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)
# 1. 전통적인 Feature Importance (전역적, 방향성 없음)
traditional_importance = rf_model.feature_importances_
print("Traditional Feature Importance:")
for name, imp in zip(X_train.columns, traditional_importance):
print(f" {name}: {imp:.4f}")
# 2. SHAP Feature Importance (지역적 설명 가능, 방향성 있음)
explainer = shap.TreeExplainer(rf_model)
shap_values = explainer.shap_values(X_test)
# 개별 샘플: 이 고객은 왜 거절? (방향성 포함)
print(f"\n개별 예측 설명 (샘플 0):")
for name, val in zip(X_train.columns, shap_values[1][0]):
direction = "승인에 +기여" if val > 0 else "거절에 +기여"
print(f" {name}: {val:.4f} ({direction})")
박시니어 씨가 두 가지 그래프를 나란히 보여주었습니다. 하나는 랜덤 포레스트의 feature_importances_를 막대그래프로 그린 것이고, 다른 하나는 SHAP의 summary plot이었습니다.
"언뜻 보면 비슷해 보이죠?"라고 박시니어 씨가 말했습니다. "둘 다 어떤 특성이 중요한지 보여주니까요.
하지만 근본적인 차이가 있어요." 첫 번째 차이는 전역 vs 지역입니다. 전통적인 feature importance는 전체 데이터셋에 대한 평균적인 중요도만 보여줍니다.
"소득이 가장 중요한 특성이다"라고 말할 수 있지만, "이 특정 고객의 예측에서 소득이 어떤 역할을 했는가"는 알 수 없습니다. 반면 SHAP은 개별 예측에 대한 설명이 가능합니다.
"이 고객의 경우, 소득이 낮아서 승인 확률이 0.2만큼 낮아졌다"와 같이 구체적인 설명을 할 수 있습니다. 두 번째 차이는 방향성입니다.
전통적인 feature importance는 "소득이 중요도 0.35이다"라고만 알려줍니다. 하지만 소득이 높으면 승인에 유리한지, 불리한지는 알 수 없습니다.
물론 상식적으로 유추할 수 있지만, 모델이 실제로 그렇게 학습했는지는 확인할 수 없습니다. SHAP은 방향성까지 알려줍니다.
SHAP 값이 양수면 예측값을 높이는 방향, 음수면 낮추는 방향으로 기여했다는 뜻입니다. 세 번째 차이는 상호작용입니다.
전통적인 feature importance는 특성 간의 상호작용을 고려하지 않습니다. 반면 SHAP은 Shapley Value의 특성상 모든 특성 조합을 고려하므로, 상호작용 효과도 반영됩니다.
"그런데 전통적인 feature importance도 유용하지 않나요?"라고 김개발 씨가 물었습니다. "물론이죠!"라고 박시니어 씨가 대답했습니다.
"전통적인 방법은 계산이 빠르고, 전체적인 모델 이해에는 충분해요. 모든 상황에서 SHAP을 쓸 필요는 없어요." 박시니어 씨가 정리했습니다.
"모델 전체의 대략적인 특성 중요도만 알고 싶다면 전통적인 방법으로 충분해요. 하지만 개별 예측을 설명해야 하거나, 특성이 예측에 어떤 방향으로 기여하는지 알아야 한다면 SHAP이나 LIME을 사용해야 해요." 김개발 씨가 고개를 끄덕였습니다.
"아, 그래서 고객에게 대출 거절 이유를 설명할 때는 SHAP이 필요했던 거군요!" "정확해요! 전통적인 feature importance로는 '소득이 중요합니다'라고만 말할 수 있지만, SHAP으로는 '당신의 소득 수준 때문에 승인 확률이 이만큼 낮아졌습니다'라고 구체적으로 설명할 수 있거든요."
실전 팁
💡 - 빠른 모델 이해에는 전통적 feature importance, 개별 예측 설명에는 SHAP을 사용하세요
- Permutation Importance도 좋은 대안이지만, 역시 방향성은 제공하지 않습니다
8. 실무 프로젝트 적용
이론을 모두 배운 김개발 씨는 이제 실제 프로젝트에 적용해볼 차례입니다. 박시니어 씨가 말했습니다.
"자, 이제 처음에 말했던 대출 승인 모델로 돌아가서, 실제로 고객에게 설명할 수 있는 시스템을 만들어볼까요?"
실무 프로젝트 적용에서는 학습한 SHAP과 LIME을 실제 비즈니스 환경에서 활용하는 방법을 다룹니다. 모델 해석 결과를 비기술직 이해관계자에게 전달하는 방법, 모니터링 시스템 구축, 그리고 해석 결과를 활용한 모델 개선 방법을 실습합니다.
다음 코드를 살펴봅시다.
import shap
import pandas as pd
def explain_prediction(model, explainer, sample, feature_names):
"""개별 예측에 대한 설명을 생성하는 함수"""
# 예측 수행
prediction = model.predict_proba(sample.reshape(1, -1))[0]
predicted_class = "승인" if prediction[1] > 0.5 else "거절"
# SHAP 값 계산
shap_values = explainer.shap_values(sample.reshape(1, -1))
# 주요 요인 추출 (상위 3개)
feature_impacts = list(zip(feature_names, shap_values[1][0]))
sorted_impacts = sorted(feature_impacts, key=lambda x: abs(x[1]), reverse=True)
# 고객 친화적 설명 생성
explanation = f"예측 결과: {predicted_class} (확률: {prediction[1]:.1%})\n"
explanation += "주요 판단 요인:\n"
for name, impact in sorted_impacts[:3]:
direction = "긍정적" if impact > 0 else "부정적"
explanation += f" - {name}: {direction} 영향 ({impact:+.3f})\n"
return explanation
# 사용 예시
print(explain_prediction(model, explainer, X_test.iloc[0].values, X_train.columns))
박시니어 씨가 김개발 씨에게 말했습니다. "자, 이제 실제로 고객센터에서 사용할 수 있는 설명 시스템을 만들어볼게요." 첫 번째 단계는 설명 생성 함수 작성입니다.
SHAP 값을 그대로 보여주면 비전문가는 이해하기 어렵습니다. "SHAP 값이 -0.234입니다"라고 말해봐야 고객은 무슨 말인지 모릅니다.
따라서 SHAP 값을 자연어로 변환하는 함수가 필요합니다. 위 코드의 explain_prediction 함수가 바로 그 역할을 합니다.
SHAP 값을 계산한 후, 가장 영향력이 큰 요인 3개를 추출하고, 각각이 긍정적인 영향인지 부정적인 영향인지 설명합니다. 두 번째 단계는 임계값 설정입니다.
박시니어 씨가 말했습니다. "모든 특성을 다 설명하면 오히려 혼란스러워요.
중요한 요인 2-3개만 전달하는 게 효과적이에요." 또한 SHAP 값이 아주 작은 경우는 생략하는 것이 좋습니다. 예를 들어 절대값이 0.01 미만인 영향은 "거의 영향 없음"으로 처리할 수 있습니다.
세 번째 단계는 용어 변환입니다. "credit_score"보다는 "신용점수", "income"보다는 "연소득"으로 표현하는 것이 고객에게 친숙합니다.
특성 이름을 사람이 이해하기 쉬운 용어로 매핑하는 딕셔너리를 만들어두면 좋습니다. 네 번째 단계는 모니터링 시스템 구축입니다.
박시니어 씨가 말했습니다. "프로덕션 환경에서는 SHAP 값의 분포가 변하는지 모니터링해야 해요.
갑자기 특정 특성의 영향력이 커지거나 작아지면, 데이터 드리프트나 모델 성능 저하의 신호일 수 있거든요." 주기적으로 SHAP 값의 평균과 분산을 계산하여 대시보드에 표시하고, 이상 징후가 감지되면 알림을 보내는 시스템을 구축할 수 있습니다. 다섯 번째 단계는 해석 결과를 활용한 모델 개선입니다.
"SHAP은 단순히 설명만을 위한 도구가 아니에요."라고 박시니어 씨가 말했습니다. "모델을 개선하는 데도 활용할 수 있어요." 예를 들어 SHAP 분석 결과 특정 특성이 예상과 반대 방향으로 작용한다면, 데이터에 문제가 있거나 모델이 잘못 학습했을 가능성이 있습니다.
이런 인사이트를 통해 데이터를 정제하거나 피처 엔지니어링을 개선할 수 있습니다. 김개발 씨가 감탄했습니다.
"단순히 설명하는 것을 넘어서 모델을 더 좋게 만드는 데도 쓸 수 있군요!" "맞아요. 그래서 모델 해석은 배포 후에만 하는 게 아니라, 개발 과정에서도 계속 활용해야 해요.
SHAP 분석을 통해 모델이 올바른 근거로 예측하고 있는지 확인하는 거죠."
실전 팁
💡 - 고객 대면용 설명은 최대 3개 요인으로 제한하세요
- SHAP 값의 변화를 모니터링하여 모델 드리프트를 조기에 감지하세요
9. 주의사항과 한계점
김개발 씨가 SHAP과 LIME을 열심히 적용하던 중, 이상한 결과를 발견했습니다. "박시니어 씨, SHAP이랑 LIME 결과가 서로 다른데요.
어떤 게 맞는 거예요?" 박시니어 씨가 모델 해석의 한계에 대해 설명하기 시작했습니다.
모델 해석의 한계점을 이해하는 것은 올바른 활용을 위해 필수적입니다. SHAP과 LIME은 강력한 도구이지만, 완벽한 해석을 보장하지는 않습니다.
특성 간 상관관계, 인과관계와 상관관계의 혼동, 해석의 일관성 문제 등 여러 한계점을 인지하고 주의해서 사용해야 합니다.
다음 코드를 살펴봅시다.
import shap
import numpy as np
from scipy.stats import pearsonr
# 주의사항 1: 상관된 특성의 SHAP 값은 해석에 주의
# 예: income과 credit_limit이 강하게 상관되어 있다면
correlation = pearsonr(X_train['income'], X_train['credit_limit'])[0]
print(f"Income-Credit Limit 상관계수: {correlation:.3f}")
if abs(correlation) > 0.7:
print("주의: 두 특성이 강하게 상관되어 있어 SHAP 값 해석에 주의 필요")
# 주의사항 2: LIME의 불안정성 확인
lime_results = []
for i in range(5): # 같은 샘플에 5번 LIME 적용
exp = lime_explainer.explain_instance(X_test.iloc[0].values, model.predict_proba)
lime_results.append(exp.as_list())
# 결과가 얼마나 일관적인지 확인
print("\n5회 LIME 실행 결과 비교:")
for i, result in enumerate(lime_results):
print(f" 실행 {i+1}: {[r[0] for r in result[:3]]}")
박시니어 씨가 김개발 씨의 화면을 살펴보았습니다. "아, 이건 자주 발생하는 상황이에요.
모델 해석 기법들의 한계를 알아야 올바르게 사용할 수 있어요." 첫 번째 한계는 상관된 특성 문제입니다. 만약 소득과 신용한도가 강하게 상관되어 있다면, 이 둘의 SHAP 값은 신뢰하기 어렵습니다.
왜냐하면 모델 입장에서 둘 중 하나만 있어도 비슷한 정보를 얻을 수 있기 때문입니다. "예를 들어 소득이 높은 사람은 대부분 신용한도도 높아요."라고 박시니어 씨가 설명했습니다.
"이 경우 모델이 소득을 주로 사용하든, 신용한도를 주로 사용하든 비슷한 예측을 할 수 있어요. 그래서 SHAP 값이 둘 사이에서 임의로 분배될 수 있어요." 이 문제를 완화하려면 상관된 특성을 제거하거나, 해석할 때 상관 관계를 고려해야 합니다.
두 번째 한계는 LIME의 불안정성입니다. LIME은 샘플링 기반이기 때문에 실행할 때마다 결과가 조금씩 달라집니다.
위 코드처럼 같은 샘플에 대해 여러 번 LIME을 실행하면, 상위 중요 특성의 순서가 바뀔 수 있습니다. "그래서 LIME 결과를 보고할 때는 여러 번 실행해서 일관되게 나오는 특성만 신뢰하는 게 좋아요."라고 박시니어 씨가 말했습니다.
세 번째 한계는 인과관계 오해입니다. SHAP과 LIME은 상관관계를 보여줄 뿐, 인과관계를 증명하지 않습니다.
"신용점수가 승인에 긍정적 영향을 미친다"는 SHAP 결과가, "신용점수를 올리면 승인 확률이 높아진다"를 의미하지는 않습니다. "모델은 데이터의 패턴을 학습한 것일 뿐이에요."라고 박시니어 씨가 강조했습니다.
"신용점수가 높은 사람들이 실제로 대출을 잘 갚았기 때문에 그런 패턴이 나온 것이지, 신용점수 자체가 원인인 건 아닐 수 있어요." 네 번째 한계는 해석의 주관성입니다. SHAP 값이 +0.1이라고 할 때, 이게 "큰" 영향인지 "작은" 영향인지는 맥락에 따라 다릅니다.
절대적인 기준이 없기 때문에, 해석하는 사람에 따라 다르게 판단할 수 있습니다. 다섯 번째 한계는 계산 비용입니다.
SHAP, 특히 KernelSHAP은 계산이 매우 느릴 수 있습니다. 실시간 서비스에서 모든 예측에 SHAP을 적용하기는 어려울 수 있습니다.
박시니어 씨가 정리했습니다. "이런 한계들을 알고 있으면 해석 결과를 더 신중하게 다룰 수 있어요.
모델 해석은 만능이 아니라 참고 자료로 활용해야 해요." 김개발 씨가 고개를 끄덕였습니다. "완벽한 도구는 없군요.
한계를 알고 쓰는 게 중요하네요."
실전 팁
💡 - 상관계수가 0.7 이상인 특성 쌍은 해석에 주의가 필요합니다
- 중요한 의사결정에는 SHAP과 LIME을 모두 적용하여 교차 검증하세요
10. 최신 트렌드와 발전
김개발 씨가 SHAP과 LIME을 마스터한 후, 박시니어 씨에게 물었습니다. "이 분야가 계속 발전하고 있다고 들었는데, 최신 트렌드는 뭔가요?" 박시니어 씨가 Explainable AI의 미래에 대해 이야기하기 시작했습니다.
Explainable AI(XAI) 분야는 빠르게 발전하고 있습니다. SHAP과 LIME 외에도 Integrated Gradients, Attention Visualization, Concept-based Explanations 등 새로운 기법들이 등장하고 있습니다.
또한 규제 강화에 따라 모델 해석의 중요성은 더욱 커지고 있습니다.
다음 코드를 살펴봅시다.
# 최신 트렌드 1: SHAP + Waterfall Plot 조합
import shap
# 최신 버전의 SHAP은 Explanation 객체 사용
explainer = shap.TreeExplainer(model)
explanation = explainer(X_test) # 새로운 API
# 개별 예측의 상세 분해
shap.plots.waterfall(explanation[0])
# 최신 트렌드 2: Beeswarm Plot (Summary Plot의 개선 버전)
shap.plots.beeswarm(explanation)
# 최신 트렌드 3: 상호작용 효과 시각화
shap.plots.scatter(explanation[:, "income"], color=explanation[:, "credit_score"])
# 최신 트렌드 4: 강제 단조성(Monotonicity) 제약이 있는 모델
# 해석 가능성을 높이기 위해 특성의 효과를 단조롭게 제한
from xgboost import XGBClassifier
mono_model = XGBClassifier(
monotone_constraints=(1, 1, 0, 1) # 소득, 신용점수는 양의 효과로 제한
)
박시니어 씨가 화이트보드에 "XAI의 미래"라고 적었습니다. "Explainable AI 분야는 정말 빠르게 발전하고 있어요.
몇 가지 트렌드를 소개해줄게요." 첫 번째 트렌드는 더 나은 시각화입니다. SHAP 라이브러리도 계속 업데이트되고 있습니다.
최신 버전에서는 Explanation 객체라는 새로운 API를 도입하여 더 직관적인 사용을 지원합니다. beeswarm plot은 기존 summary plot의 개선 버전으로, 더 많은 정보를 효과적으로 전달합니다.
두 번째 트렌드는 상호작용 효과 분석입니다. 단순히 개별 특성의 효과뿐만 아니라, 특성 간의 상호작용 효과도 중요해지고 있습니다.
"소득 효과가 신용점수에 따라 달라지는가?" 같은 질문에 답할 수 있습니다. scatter plot에 color 파라미터를 추가하면 이런 상호작용을 시각화할 수 있습니다.
세 번째 트렌드는 해석 가능한 모델 설계입니다. 박시니어 씨가 말했습니다.
"사후 해석보다 애초에 해석 가능한 모델을 만드는 게 더 좋을 수 있어요." 예를 들어 XGBoost의 monotone_constraints 파라미터를 사용하면, 특정 특성이 예측에 미치는 효과를 단조롭게 제한할 수 있습니다. "소득이 높을수록 항상 승인에 유리하다"는 도메인 지식을 모델에 반영하는 것입니다.
네 번째 트렌드는 Attention 기반 해석입니다. 딥러닝, 특히 Transformer 모델에서는 Attention 가중치를 활용한 해석이 활발히 연구되고 있습니다.
모델이 어떤 입력에 "주목"했는지 시각화할 수 있습니다. 다섯 번째 트렌드는 개념 기반 설명입니다.
TCAV(Testing with Concept Activation Vectors) 같은 기법은 개별 특성이 아닌 고수준 개념으로 설명합니다. "이 이미지가 고양이로 분류된 것은 '털이 있는' 개념과 '귀가 뾰족한' 개념 때문입니다"와 같이 더 사람에게 자연스러운 설명을 제공합니다.
여섯 번째 트렌드는 규제 대응입니다. 유럽 AI Act, 미국의 AI 관련 규제 등이 강화되면서, 모델 해석은 선택이 아닌 필수가 되고 있습니다.
특히 고위험 AI 시스템에서는 의사결정에 대한 설명이 법적으로 요구됩니다. 박시니어 씨가 마무리했습니다.
"SHAP과 LIME은 시작일 뿐이에요. 이 분야를 계속 공부하면 앞으로 더 좋은 도구들을 활용할 수 있을 거예요." 김개발 씨의 눈이 반짝였습니다.
"정말 흥미로운 분야네요! 계속 공부해야겠어요." 박시니어 씨가 웃으며 말했습니다.
"그 자세 좋아요. 오늘 배운 것들을 실제 프로젝트에 적용해보면서 경험을 쌓아보세요.
그게 가장 빠른 성장 방법이에요."
실전 팁
💡 - SHAP 라이브러리는 자주 업데이트되니 최신 버전을 유지하세요
- 해석 가능성과 성능의 균형을 고려하여 모델을 설계하세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
vLLM 통합 완벽 가이드
대규모 언어 모델 추론을 획기적으로 가속화하는 vLLM의 설치부터 실전 서비스 구축까지 다룹니다. PagedAttention과 연속 배칭 기술로 GPU 메모리를 효율적으로 활용하는 방법을 배웁니다.
Web UI Demo 구축 완벽 가이드
Gradio를 활용하여 머신러닝 모델과 AI 서비스를 위한 웹 인터페이스를 구축하는 방법을 다룹니다. 코드 몇 줄만으로 전문적인 데모 페이지를 만들고 배포하는 과정을 초급자도 쉽게 따라할 수 있도록 설명합니다.
Sandboxing & Execution Control 완벽 가이드
AI 에이전트가 코드를 실행할 때 반드시 필요한 보안 기술인 샌드박싱과 실행 제어에 대해 알아봅니다. 격리된 환경에서 안전하게 코드를 실행하고, 악성 동작을 탐지하는 방법을 단계별로 설명합니다.
Voice Design then Clone 워크플로우 완벽 가이드
AI 음성 합성에서 일관된 캐릭터 음성을 만드는 Voice Design then Clone 워크플로우를 설명합니다. 참조 음성 생성부터 재사용 가능한 캐릭터 구축까지 실무 활용법을 다룹니다.
Tool Use 완벽 가이드 - Shell, Browser, DB 실전 활용
AI 에이전트가 외부 도구를 활용하여 셸 명령어 실행, 브라우저 자동화, 데이터베이스 접근 등을 수행하는 방법을 배웁니다. 실무에서 바로 적용할 수 있는 패턴과 베스트 프랙티스를 담았습니다.