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 {
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