Skip to content

Commit 6db1480

Browse files
committed
up
1 parent 3a8589c commit 6db1480

3 files changed

Lines changed: 141 additions & 119 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
# MyST build outputs
22
_build
3+
4+
# 저장된 모델 무시
5+
*.pkl

end2end_ml_project.ipynb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2676,7 +2676,8 @@
26762676
"다음 할 일은 모델을 실전에 투입했을 때의 모델 성능 예측하기이며,\n",
26772677
"여기에 테스트셋을 활용한다.\n",
26782678
"\n",
2679-
"아래 코드는 테스트셋에 대한 최종 모델의 RMSE를 계산한다.\n",
2679+
"아래 코드는 \n",
2680+
"랜덤 탐색으로 확인된 최적의 모델의 테스트셋에 대한 RMSE를 계산한다.\n",
26802681
"테스트셋 또한 입력 데이터셋과 타깃셋으로 먼저 구분한 다음에 모델 예측에 활용됨에 주의한다."
26812682
]
26822683
},

notebooks/code-end2end_ml_project.ipynb

Lines changed: 136 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -27554,9 +27554,16 @@
2755427554
"## 최적 모델 활용 및 평가"
2755527555
]
2755627556
},
27557+
{
27558+
"cell_type": "markdown",
27559+
"metadata": {},
27560+
"source": [
27561+
"랜덤 탐색으로 확인된 최적의 모델을 활용하여 최종 평가를 진행한다."
27562+
]
27563+
},
2755727564
{
2755827565
"cell_type": "code",
27559-
"execution_count": null,
27566+
"execution_count": 133,
2756027567
"metadata": {},
2756127568
"outputs": [],
2756227569
"source": [
@@ -27570,16 +27577,28 @@
2757027577
"### 테스트셋 활용"
2757127578
]
2757227579
},
27580+
{
27581+
"cell_type": "markdown",
27582+
"metadata": {},
27583+
"source": [
27584+
"이제 더 이상의 훈련을 진행할 필요가 없을 정도로 훈련된 모델의 성능에\n",
27585+
"만족한다고 가정하자.\n",
27586+
"다음 할 일은 모델을 실전에 투입했을 때의 모델 성능 예측하기이며,\n",
27587+
"여기에 테스트셋을 활용한다.\n",
27588+
"테스트셋 또한 입력 데이터셋과 타깃셋으로 먼저 구분되어야 하고,\n",
27589+
"모델 자체에 전처리 기능이 포함되어 있음에 주의한다."
27590+
]
27591+
},
2757327592
{
2757427593
"cell_type": "code",
27575-
"execution_count": 145,
27594+
"execution_count": 134,
2757627595
"metadata": {},
2757727596
"outputs": [
2757827597
{
2757927598
"name": "stdout",
2758027599
"output_type": "stream",
2758127600
"text": [
27582-
"41445.533268606625\n"
27601+
"41422.168800999665\n"
2758327602
]
2758427603
}
2758527604
],
@@ -27597,14 +27616,24 @@
2759727616
"cell_type": "markdown",
2759827617
"metadata": {},
2759927618
"source": [
27600-
"We can compute a 95% confidence interval for the test RMSE using SciPy's `bootstrap()` function:"
27619+
"SciPy의 `bootstrap()` 함수를 사용하여 테스트 RMSE에 대한 \n",
27620+
"95% 신뢰구간<font size='2'>confidence interval</font>를 계산하면 다음과 같다.\n",
27621+
"신뢰구간은 줄여서 CI라 한다."
2760127622
]
2760227623
},
2760327624
{
2760427625
"cell_type": "code",
27605-
"execution_count": 146,
27626+
"execution_count": 135,
2760627627
"metadata": {},
27607-
"outputs": [],
27628+
"outputs": [
27629+
{
27630+
"name": "stdout",
27631+
"output_type": "stream",
27632+
"text": [
27633+
"95% CI for RMSE: (39487.5429, 43654.0546)\n"
27634+
]
27635+
}
27636+
],
2760827637
"source": [
2760927638
"from scipy.stats import bootstrap\n",
2761027639
"\n",
@@ -27615,111 +27644,67 @@
2761527644
"squared_errors = (final_predictions - y_test) ** 2\n",
2761627645
"boot_result = bootstrap([squared_errors], rmse, confidence_level=confidence,\n",
2761727646
" random_state=42)\n",
27618-
"rmse_lower, rmse_upper = boot_result.confidence_interval"
27647+
"rmse_lower, rmse_upper = boot_result.confidence_interval\n",
27648+
"print(f\"95% CI for RMSE: ({rmse_lower:.4f}, {rmse_upper:.4f})\")"
2761927649
]
2762027650
},
2762127651
{
27622-
"cell_type": "code",
27623-
"execution_count": 147,
27652+
"cell_type": "markdown",
2762427653
"metadata": {},
27625-
"outputs": [
27626-
{
27627-
"name": "stdout",
27628-
"output_type": "stream",
27629-
"text": [
27630-
"95% CI for RMSE: (39520.9572, 43701.7681)\n"
27631-
]
27632-
}
27633-
],
2763427654
"source": [
27635-
"print(f\"95% CI for RMSE: ({rmse_lower:.4f}, {rmse_upper:.4f})\")"
27655+
"### 모델 기타 활용법"
2763627656
]
2763727657
},
2763827658
{
2763927659
"cell_type": "markdown",
2764027660
"metadata": {},
2764127661
"source": [
27642-
"### 모델 기타 활용법"
27662+
"머신러닝 모델은 단순히 예측을 위해서만 사용되지는 않는다.\n",
27663+
"모델 종류에 따라 예측값 계산과 함께 다른 기능을 제공하기도 한다.\n",
27664+
"\n",
27665+
"예를 들어, 훈련이 잘 진행된 랜덤 포레스트 모델은 \n",
27666+
"입력 데이터셋의 각 특성이 모델이 예측값을 계산할 때 얼마나 많이 기여하는가를\n",
27667+
"특성 중요도라는 기준으로 훈련 과정중에 평가한다.\n",
27668+
"\n",
27669+
"캘리포니아 주택가격 예측을 위해 최적화된 랜덤 포레스트 모델은\n",
27670+
"`feature_importances_` 속성에 특성별 중요도를 저장해 두며,\n",
27671+
"확인 결과 '중위소득의 로그 변환값'(`log__median_income`) 특성의 중요도가 가장 높다. 그 다음으로는 해안 근접도 특성 중에서 특히 '내륙'(`INLAND`) 특성의 중요도가 높다.\n",
27672+
"언급된 나머지 8개 특성은 침실 비율, 가구당 방 수, 가구당 인원, 그리고 5 개의 군집 번호 등이며,\n",
27673+
"중위소득의 로그 변환값 특성의 중요도가 압도적으로 높다."
2764327674
]
2764427675
},
2764527676
{
2764627677
"cell_type": "code",
27647-
"execution_count": null,
27678+
"execution_count": 136,
2764827679
"metadata": {},
2764927680
"outputs": [
2765027681
{
2765127682
"data": {
2765227683
"text/plain": [
27653-
"[(np.float64(0.18599734460509476), 'log__median_income'),\n",
27654-
" (np.float64(0.07338850855844489), 'cat__ocean_proximity_INLAND'),\n",
27655-
" (np.float64(0.06556941990883976), 'bedrooms__ratio'),\n",
27656-
" (np.float64(0.053648710076725316), 'rooms_per_house__ratio'),\n",
27657-
" (np.float64(0.04598870861894749), 'people_per_house__ratio'),\n",
27658-
" (np.float64(0.04175269214442519), 'geo__Cluster 30 similarity'),\n",
27659-
" (np.float64(0.025976797232869678), 'geo__Cluster 25 similarity'),\n",
27660-
" (np.float64(0.023595895886342255), 'geo__Cluster 36 similarity'),\n",
27661-
" (np.float64(0.02021056221732893), 'geo__Cluster 9 similarity'),\n",
27662-
" (np.float64(0.01860691707666145), 'geo__Cluster 34 similarity'),\n",
27663-
" (np.float64(0.018137988374628867), 'geo__Cluster 37 similarity'),\n",
27664-
" (np.float64(0.01740435316632675), 'geo__Cluster 18 similarity'),\n",
27665-
" (np.float64(0.016778386143844894), 'geo__Cluster 1 similarity'),\n",
27666-
" (np.float64(0.015459009666188978), 'geo__Cluster 7 similarity'),\n",
27667-
" (np.float64(0.015325731028175924), 'geo__Cluster 32 similarity'),\n",
27668-
" (np.float64(0.015073772015038348), 'geo__Cluster 13 similarity'),\n",
27669-
" (np.float64(0.014272160962173805), 'geo__Cluster 35 similarity'),\n",
27670-
" (np.float64(0.014180636461860479), 'geo__Cluster 0 similarity'),\n",
27671-
" (np.float64(0.013746364498238989), 'geo__Cluster 3 similarity'),\n",
27672-
" (np.float64(0.01357230570846952), 'geo__Cluster 28 similarity'),\n",
27673-
" (np.float64(0.01294034969422872), 'geo__Cluster 26 similarity'),\n",
27674-
" (np.float64(0.012738123746761944), 'geo__Cluster 31 similarity'),\n",
27675-
" (np.float64(0.011654237215152624), 'geo__Cluster 19 similarity'),\n",
27676-
" (np.float64(0.011628003598059723), 'geo__Cluster 6 similarity'),\n",
27677-
" (np.float64(0.011134113333125398), 'geo__Cluster 24 similarity'),\n",
27678-
" (np.float64(0.011042979326385049), 'remainder__housing_median_age'),\n",
27679-
" (np.float64(0.010907388443940418), 'geo__Cluster 43 similarity'),\n",
27680-
" (np.float64(0.010847192663592166), 'geo__Cluster 44 similarity'),\n",
27681-
" (np.float64(0.010592244492858267), 'geo__Cluster 10 similarity'),\n",
27682-
" (np.float64(0.010512467290844922), 'geo__Cluster 23 similarity'),\n",
27683-
" (np.float64(0.01045866561538645), 'geo__Cluster 41 similarity'),\n",
27684-
" (np.float64(0.010261910692851673), 'geo__Cluster 40 similarity'),\n",
27685-
" (np.float64(0.009757306983097491), 'geo__Cluster 2 similarity'),\n",
27686-
" (np.float64(0.00965993322211448), 'geo__Cluster 12 similarity'),\n",
27687-
" (np.float64(0.009574969190852869), 'geo__Cluster 14 similarity'),\n",
27688-
" (np.float64(0.008199144719918425), 'geo__Cluster 20 similarity'),\n",
27689-
" (np.float64(0.008141941480860806), 'geo__Cluster 33 similarity'),\n",
27690-
" (np.float64(0.007596761219964691), 'geo__Cluster 8 similarity'),\n",
27691-
" (np.float64(0.0075762980128490295), 'geo__Cluster 22 similarity'),\n",
27692-
" (np.float64(0.007346290789504319), 'geo__Cluster 39 similarity'),\n",
27693-
" (np.float64(0.006898774333063982), 'geo__Cluster 4 similarity'),\n",
27694-
" (np.float64(0.0067947318450798395), 'log__total_rooms'),\n",
27695-
" (np.float64(0.006514889773323568), 'log__population'),\n",
27696-
" (np.float64(0.006350528211987125), 'geo__Cluster 27 similarity'),\n",
27697-
" (np.float64(0.006337558749902337), 'geo__Cluster 16 similarity'),\n",
27698-
" (np.float64(0.006231053672395539), 'geo__Cluster 38 similarity'),\n",
27699-
" (np.float64(0.0061213483458714855), 'log__households'),\n",
27700-
" (np.float64(0.005849842001582111), 'log__total_bedrooms'),\n",
27701-
" (np.float64(0.0056783104666850125), 'geo__Cluster 15 similarity'),\n",
27702-
" (np.float64(0.005479729990673467), 'geo__Cluster 29 similarity'),\n",
27703-
" (np.float64(0.005348325088535128), 'geo__Cluster 42 similarity'),\n",
27704-
" (np.float64(0.004866251452445486), 'geo__Cluster 17 similarity'),\n",
27705-
" (np.float64(0.004495340541933027), 'geo__Cluster 11 similarity'),\n",
27706-
" (np.float64(0.004418821635620684), 'geo__Cluster 5 similarity'),\n",
27707-
" (np.float64(0.0035344732505291285), 'geo__Cluster 21 similarity'),\n",
27708-
" (np.float64(0.001832424657341851), 'cat__ocean_proximity_<1H OCEAN'),\n",
27709-
" (np.float64(0.0015282226447271795), 'cat__ocean_proximity_NEAR OCEAN'),\n",
27710-
" (np.float64(0.0004325970342247361), 'cat__ocean_proximity_NEAR BAY'),\n",
27711-
" (np.float64(3.0190221102670295e-05), 'cat__ocean_proximity_ISLAND')]"
27684+
"[(np.float64(0.18836603202647126), 'log__median_income'),\n",
27685+
" (np.float64(0.07795960969938898), 'cat__ocean_proximity_INLAND'),\n",
27686+
" (np.float64(0.06110388595864347), 'bedrooms__ratio'),\n",
27687+
" (np.float64(0.05772194900488602), 'rooms_per_house__ratio'),\n",
27688+
" (np.float64(0.04569274355282605), 'people_per_house__ratio'),\n",
27689+
" (np.float64(0.041977095119231075), 'geo__Cluster 30 similarity'),\n",
27690+
" (np.float64(0.024893290428216707), 'geo__Cluster 9 similarity'),\n",
27691+
" (np.float64(0.02349145973584661), 'geo__Cluster 36 similarity'),\n",
27692+
" (np.float64(0.021384735075780065), 'geo__Cluster 18 similarity'),\n",
27693+
" (np.float64(0.019231937253583756), 'geo__Cluster 3 similarity')]"
2771227694
]
2771327695
},
27696+
"execution_count": 136,
2771427697
"metadata": {},
27715-
"output_type": "display_data"
27698+
"output_type": "execute_result"
2771627699
}
2771727700
],
2771827701
"source": [
2771927702
"feature_importances = final_model[\"random_forest\"].feature_importances_\n",
27720-
"sorted(zip(feature_importances,\n",
27721-
" final_model[\"preprocessing\"].get_feature_names_out()),\n",
27722-
" reverse=True)"
27703+
"\n",
27704+
"important_features = sorted(zip(feature_importances,\n",
27705+
" final_model[\"preprocessing\"].get_feature_names_out()),\n",
27706+
" reverse=True)\n",
27707+
"important_features[:10]"
2772327708
]
2772427709
},
2772527710
{
@@ -27733,12 +27718,48 @@
2773327718
"cell_type": "markdown",
2773427719
"metadata": {},
2773527720
"source": [
27736-
"Save the final model:"
27721+
"최적의 모델을 훈련시키는 과정이 매우 길 수 있다.\n",
27722+
"따라서 한 번 훈련된 좋은 모델은 파일로 저장해 놓아야 한다.\n",
27723+
"그러면 모델을 활용하고자 할 때 저장된 파일을 모델로 불러와서\n",
27724+
"훈련 없이 바로 활용할 수 있다.\n",
27725+
"또한 새롭게 훈련시킨 모델이 적절하지 않다고 판단되어\n",
27726+
"이전 버전의 모델로 되돌려야 하는 상황이 발생할 수도 있기에\n",
27727+
"잘 훈련된 모델의 저장은 필수적이다.\n",
27728+
"\n",
27729+
"모델의 저장과 불러오기는 각각 `joblib` 모듈의\n",
27730+
"`dump()` 함수와 `load()` 함수를 활용한다.\n",
27731+
"\n",
27732+
"- 저장하기\n",
27733+
"\n",
27734+
" ```python\n",
27735+
" import joblib\n",
27736+
" joblib.dump(final_model, \"my_california_housing_model.pkl\")\n",
27737+
" ```\n",
27738+
"- 불러오기와 활용\n",
27739+
"\n",
27740+
" ```python\n",
27741+
" final_model_reloaded = joblib.load(\"my_california_housing_model.pkl\")\n",
27742+
" final_model_reloaded.predict(X_test)\n",
27743+
" ```"
27744+
]
27745+
},
27746+
{
27747+
"cell_type": "markdown",
27748+
"metadata": {},
27749+
"source": [
27750+
"**모델 저장**"
27751+
]
27752+
},
27753+
{
27754+
"cell_type": "markdown",
27755+
"metadata": {},
27756+
"source": [
27757+
"아래 코드를 실행하면 지정된 경로에 최적의 모델을 pickle 파일로 저장한다."
2773727758
]
2773827759
},
2773927760
{
2774027761
"cell_type": "code",
27741-
"execution_count": 144,
27762+
"execution_count": 137,
2774227763
"metadata": {},
2774327764
"outputs": [
2774427765
{
@@ -27747,7 +27768,7 @@
2774727768
"['my_california_housing_model.pkl']"
2774827769
]
2774927770
},
27750-
"execution_count": 144,
27771+
"execution_count": 137,
2775127772
"metadata": {},
2775227773
"output_type": "execute_result"
2775327774
}
@@ -27762,52 +27783,49 @@
2776227783
"cell_type": "markdown",
2776327784
"metadata": {},
2776427785
"source": [
27765-
"Now you can deploy this model to production. For example, the following code could be a script that would run in production:"
27786+
"저장된 모델을 다시 불러와 바로 실전에 투입할 수 있다.\n",
27787+
"다만, 저장된 모델 활용에 필요한 라이브러리 임포트를 함께 해야 한다.\n",
27788+
"그렇지 않으면 모델 불러오고 활용할 때 필요한 클래스나 함수가 정의되지 않아 오류가 발생한다."
2776627789
]
2776727790
},
2776827791
{
2776927792
"cell_type": "code",
27770-
"execution_count": 145,
27793+
"execution_count": 140,
2777127794
"metadata": {},
27772-
"outputs": [],
27795+
"outputs": [
27796+
{
27797+
"name": "stdout",
27798+
"output_type": "stream",
27799+
"text": [
27800+
"[440208.11 457822.08 106671. 100105. 330637.02]\n"
27801+
]
27802+
}
27803+
],
2777327804
"source": [
2777427805
"import joblib\n",
2777527806
"\n",
27776-
"# extra code – excluded for conciseness\n",
27777-
"from sklearn.cluster import KMeans\n",
27778-
"from sklearn.base import BaseEstimator, TransformerMixin\n",
27779-
"from sklearn.metrics.pairwise import rbf_kernel\n",
27807+
"### 중요 안내 시작 ###\n",
27808+
"# 저장된 모델 활용에 필요한 라이브러리 임포트를 함께 해야 함.\n",
27809+
"# 그렇지 않으면 모델 로드 시 필요한 클래스나 함수가 정의되지 않아 오류 발생\n",
2778027810
"\n",
27781-
"def column_ratio(X):\n",
27782-
" return X[:, [0]] / X[:, [1]]\n",
27811+
"# from sklearn.cluster import KMeans\n",
27812+
"# from sklearn.base import BaseEstimator, TransformerMixin\n",
27813+
"# from sklearn.metrics.pairwise import rbf_kernel\n",
27814+
"\n",
27815+
"# def column_ratio(X):\n",
27816+
"# return X[:, [0]] / X[:, [1]]\n",
2778327817
"\n",
2778427818
"#class ClusterSimilarity(BaseEstimator, TransformerMixin):\n",
2778527819
"# [...]\n",
27820+
"### 중요 안내 종료 ###\n",
2778627821
"\n",
27822+
"# 모델 불러오기\n",
2778727823
"final_model_reloaded = joblib.load(\"my_california_housing_model.pkl\")\n",
2778827824
"\n",
27789-
"new_data = housing.iloc[:5] # pretend these are new districts\n",
27790-
"predictions = final_model_reloaded.predict(new_data)"
27791-
]
27792-
},
27793-
{
27794-
"cell_type": "code",
27795-
"execution_count": 146,
27796-
"metadata": {},
27797-
"outputs": [
27798-
{
27799-
"data": {
27800-
"text/plain": [
27801-
"array([441046.12, 454713.09, 104832. , 101316. , 336181.05])"
27802-
]
27803-
},
27804-
"execution_count": 146,
27805-
"metadata": {},
27806-
"output_type": "execute_result"
27807-
}
27808-
],
27809-
"source": [
27810-
"predictions"
27825+
"# 새로운 데이터에 대한 예측에 활용 예제\n",
27826+
"new_data = housing.iloc[:5] # 새로운 데이터라고 가정\n",
27827+
"predictions = final_model_reloaded.predict(new_data)\n",
27828+
"print(predictions)"
2781127829
]
2781227830
}
2781327831
],

0 commit comments

Comments
 (0)