Skip to content

Commit f6feccb

Browse files
committed
up
1 parent 6db1480 commit f6feccb

2 files changed

Lines changed: 65 additions & 38 deletions

File tree

end2end_ml_project.ipynb

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2753,23 +2753,19 @@
27532753
},
27542754
{
27552755
"cell_type": "markdown",
2756-
"id": "41d39ca3-31c0-41dd-a19c-da009338005f",
27572756
"metadata": {},
27582757
"source": [
2759-
":::{warning}\n",
2760-
"\n",
2761-
"여기서 사용하는 모델이 전처리와 함게 하나의 파이프라인으로 묶여 있음에 주의한다.\n",
2758+
"특성 중요도는 전처리 변환기와 아무 상관이 없으며, 랜덤 포레스트 모델 등 일부 모델에서만 훈련중에 함께 저장된다.\n",
27622759
"\n",
2760+
"아래 코드는 `final_model`에서 랜덤 포레스트 모델의 이름이 `\"random_forest\"`로 지정되었기에 해당 이름을 이용하여 인덱싱 한 다음에 특성 중요도를 확인한다."
2761+
]
2762+
},
2763+
{
2764+
"cell_type": "markdown",
2765+
"metadata": {},
2766+
"source": [
27632767
"```python\n",
2764-
"full_pipeline = Pipeline([\n",
2765-
" (\"preprocessing\", preprocessing),\n",
2766-
" (\"random_forest\", RandomForestRegressor(random_state=42)),\n",
2767-
"])\n",
2768-
"\n",
2769-
"특성 중요도와 같이 모델이 예측 훈련을 하는 동안 학습한 데이터는\n",
2770-
"변환기가 아닌 예측기에 저장된다.\n",
2771-
"즉, 위 파이프라인에서 `\"random_forest\"` 이름이 가리키는 `RandomForestRegressor`\n",
2772-
"예측기에 저장된다.\n",
2768+
"final_model[\"random_forest\"].feature_importances_\n",
27732769
"```"
27742770
]
27752771
},
@@ -2850,31 +2846,30 @@
28502846
"id": "80202587-a23e-4690-9f5a-a298c72e5f19",
28512847
"metadata": {},
28522848
"source": [
2853-
"(2) 결측치 처리\n",
2849+
"(2) `total_bedrooms`에 포함된 결측치를 다르게 처리할 경우 모델의 성능에 차이가 발생하는지 여부룰 확인하라. \n",
28542850
"\n",
2855-
"- 옵션 1: 결측치를 포함하는 구역 샘플 삭제\n",
2851+
"가. 결측치를 포함하는 구역 샘플 삭제\n",
28562852
"\n",
2857-
" ```python\n",
2858-
" housing_option1 = housing.copy()\n",
2859-
" housing_option1.dropna(subset=[\"total_bedrooms\"], inplace=True)\n",
2860-
" ```\n",
2853+
"```python\n",
2854+
"housing.dropna(subset=[\"total_bedrooms\"], inplace=True)\n",
2855+
"```\n",
28612856
"\n",
2862-
"- 옵션 2: 결측치가 포함된 특성 삭제\n",
2857+
"나. 결측치가 포함된 특성 자체 제거\n",
28632858
"\n",
2864-
" ```python\n",
2865-
" housing_option2 = housing.copy()\n",
2866-
" housing_option2.drop(\"total_bedrooms\", axis=1, inplace=True)\n",
2867-
" ```"
2859+
"```python\n",
2860+
"housing.drop(\"total_bedrooms\", axis=1, inplace=True)\n",
2861+
"```"
28682862
]
28692863
},
28702864
{
28712865
"cell_type": "markdown",
28722866
"metadata": {},
28732867
"source": [
2874-
"(3) OrdinalEncoder 활용\n",
2868+
"(3) 해안 근접도 특성에 대해 원-핫 인코딩 대신 `OrdinalEncoder` 변환기 객체를 적용할 경우 훈련된 모델의 성능이 어떻게 달라지며, 성능의 차이에 대한 근거를 추정하라.\n",
28752869
"\n",
28762870
"```python\n",
28772871
"housing_cat = housing[[\"ocean_proximity\"]]\n",
2872+
"\n",
28782873
"from sklearn.preprocessing import OrdinalEncoder\n",
28792874
"ordinal_encoder = OrdinalEncoder()\n",
28802875
"housing_cat_encoded = ordinal_encoder.fit_transform(housing_cat)\n",
@@ -2885,26 +2880,47 @@
28852880
"cell_type": "markdown",
28862881
"metadata": {},
28872882
"source": [
2888-
"(4) `preprocessing`과 예측기 분리.\n",
2883+
"(4) 아래 코드는 `preprocessing` 변환기 파이프라인과 랜덤 포레스트 회귀 모델을 하나로 묶은 모델을 지정한다.\n",
28892884
"\n",
2890-
"- `preprocessing`을 이용하여 먼저 데이터셋 변환\n",
2891-
"- 변환된 데이터셋을 이용하여 모델 훈련"
2892-
]
2893-
},
2894-
{
2895-
"cell_type": "markdown",
2896-
"metadata": {},
2897-
"source": [
2898-
":::{note} 변환기 포함 파이프라인 모델의 장단점\n",
2885+
"```python\n",
2886+
"full_pipeline = Pipeline([\n",
2887+
" (\"preprocessing\", preprocessing),\n",
2888+
" (\"random_forest\", RandomForestRegressor(random_state=42)),\n",
2889+
"])\n",
2890+
"```\n",
28992891
"\n",
29002892
"전처리 변환기와 예측기 모델을 하나로 묶은 파이프라인 머신러닝 모델의 장점은 다음과 같다.\n",
29012893
"\n",
29022894
"- 코드 간소화: 전처리와 훈련 과정을 하나의 객체로 묶어 코드가 깔끔해지고 관리가 쉬워짐.\n",
29032895
"- 데이터 누설 방지: 교차 검증 시 각 폴드에 맞게 전처리가 독립적으로 수행되어 검증 데이터가 훈련에 반영되는 것을 막음\n",
29042896
"- 모델 미세 조정 용이: 예측기뿐만 아니라 변환기의 특성까지 한 번에 고려하며 교차 검증 진행 가능 가능\n",
29052897
"\n",
2906-
"반면에 단점으로 중간 단계의 변환 결과를 즉각적으로 확인하기 어려워 디버깅이 까다롭다는 점과, 그리드 탐색 시 전처리 과정이 매번 중복 수행되어 연산 시간(비용)이 다소 증가할 수 있다는 점을 고려해야 한다.\n",
2907-
":::"
2898+
"반면에 몇 가지 단점을 갖는다.\n",
2899+
"\n",
2900+
"1. 중간 전처리 결과(데이터)를 직접 눈으로 확인하기 어려움\n",
2901+
"\n",
2902+
" - 가장 큰 단점임.\n",
2903+
" - 원본 데이터가 파이프라인의 `fit_predict`를 통과하면 바로 최종 예측값이 나와버리기 때문에, 중간에 원-핫 인코딩이 잘 되었는지, 스케일링은 정상적으로 되었는지 중간 데이터프레임 형태를 디버깅하거나 시각화하기가 까다로움\n",
2904+
" - 이를 보려면 결국 파이프라인을 쪼개서 `transform`만 따로 실행해봐야 함.\n",
2905+
"\n",
2906+
"2. 하이퍼파라미터 튜닝 시 이름이 길고 복잡해짐\n",
2907+
"\n",
2908+
" - `GridSearchCV` 등에서 모델 미세 조정할 때, 파라미터 이름을 지정하는 방식이 매우 길어짐.\n",
2909+
" - (예: 모델만 있을 때) `max_features`\n",
2910+
" - (파이프라인 결합 시) `random_forest__max_features`, `preprocessing__geo__n_clusters` 같이 `단계이름__파라미터이름` 형태의 이중 밑줄(`__`) 문법을 사용해야 해서 코드가 길어지고 오타가 나기 쉬움.\n",
2911+
"\n",
2912+
"3. 매우 큰 데이터셋에서 튜닝 시 반복 연산(시간 효율성 저하)\n",
2913+
"\n",
2914+
" - 교차 검증이나 그리드 서치를 돌릴 때, 파이프라인 전체를 통째로 넣으면 모델의 파라미터만 바꾸면서 실험할 때도 무거운 앞단 전처리(예: KMeans 클러스터링, 특성 추가 등)를 반복해서 매번 다시 계산하게 될 수 있음.\n",
2915+
" - 단, 사이킷런 파이프라인의 `memory` 인자를 사용하여 중간 변환 결과를 캐싱(저장)하면 이 문제는 해결할 수 있음.\n",
2916+
"\n",
2917+
"4. 예측 결과 분석(변수 중요도 등) 추출의 번거로움\n",
2918+
"\n",
2919+
" - `RandomForest`나 `XGBoost` 같은 트리를 학습시킨 후 \"어떤 특성이 가장 중요했지?\"(`feature_importances_`)를 물어보려면, 모델을 파이프라인 껍질 안에서 꺼내와야 함.\n",
2920+
" - 더불어, 전처리 과정에서 새로 생겨난 컬럼 이름들(더미 변수 등)까지 매칭시켜주려면 `pipeline.named_steps['전처리'].get_feature_names_out()` 같은 복잡한 코드를 추가로 작성해야 함.\n",
2921+
"\n",
2922+
"이제 `preprocessing`과 예측기를 분리하여 훈련을 진행하는 코드를 작성하여,\n",
2923+
"앞서 언급한 `full_pipeline`의 장단점을 확인하라."
29082924
]
29092925
}
29102926
],

notebooks/code-end2end_ml_project.ipynb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27673,9 +27673,18 @@
2767327673
"중위소득의 로그 변환값 특성의 중요도가 압도적으로 높다."
2767427674
]
2767527675
},
27676+
{
27677+
"cell_type": "markdown",
27678+
"metadata": {},
27679+
"source": [
27680+
"특성 중요도는 전처리 변환기와 아무 상관이 없으며, 랜덤 포레스트 모델 등 일부 모델에서만 훈련중에 함께 저장된다.\n",
27681+
"\n",
27682+
"아래 코드는 `final_model`에서 랜덤 포레스트 모델의 이름이 `\"random_forest\"`로 지정되었기에 해당 이름을 이용하여 인덱싱 한 다음에 특성 중요도를 확인한다."
27683+
]
27684+
},
2767627685
{
2767727686
"cell_type": "code",
27678-
"execution_count": 136,
27687+
"execution_count": null,
2767927688
"metadata": {},
2768027689
"outputs": [
2768127690
{
@@ -27699,8 +27708,10 @@
2769927708
}
2770027709
],
2770127710
"source": [
27711+
"# 모델에 포함된 랜덤 포레스트 모델을 이용한 특성 중요도 추출\n",
2770227712
"feature_importances = final_model[\"random_forest\"].feature_importances_\n",
2770327713
"\n",
27714+
"# 특성 중요도와 해당 특성명을 함께 묶어서 중요도 기준으로 정렬\n",
2770427715
"important_features = sorted(zip(feature_importances,\n",
2770527716
" final_model[\"preprocessing\"].get_feature_names_out()),\n",
2770627717
" reverse=True)\n",

0 commit comments

Comments
 (0)