looh2 commited on
Commit
eb1604d
·
1 Parent(s): 2c9d478

added ml_ridge_regression

Browse files
app.py CHANGED
@@ -15,6 +15,7 @@ from routes.ML_LinearRegression_ChurnPredictor import router as linear_regressio
15
  from routes.ML_LogisticRegression_ChurnPredictor import router as logistic_regression_router
16
  from routes.ML_DecisionTree_IrisClassifier import router as iris_router
17
  from routes.ML_RandomForest_TaxiPredictor import router as random_forest_router
 
18
 
19
  from routes.DL_RNN_StockPricePredictor import router as rnn_stock_router
20
  from routes.DL_CNN_NumberRecognition import router as cnn_router
@@ -50,6 +51,7 @@ app.include_router(sentiment_router, dependencies=_auth)
50
  app.include_router(linear_regression_router, dependencies=_auth)
51
  app.include_router(logistic_regression_router, dependencies=_auth)
52
  app.include_router(random_forest_router, dependencies=_auth)
 
53
  app.include_router(cnn_router, dependencies=_auth)
54
  app.include_router(iris_router, dependencies=_auth)
55
  app.include_router(nlp_collaborative_filter_router, dependencies=_auth)
 
15
  from routes.ML_LogisticRegression_ChurnPredictor import router as logistic_regression_router
16
  from routes.ML_DecisionTree_IrisClassifier import router as iris_router
17
  from routes.ML_RandomForest_TaxiPredictor import router as random_forest_router
18
+ from routes.ML_RidgeRegression_HousePricePredictor import router as ridge_regression_router
19
 
20
  from routes.DL_RNN_StockPricePredictor import router as rnn_stock_router
21
  from routes.DL_CNN_NumberRecognition import router as cnn_router
 
51
  app.include_router(linear_regression_router, dependencies=_auth)
52
  app.include_router(logistic_regression_router, dependencies=_auth)
53
  app.include_router(random_forest_router, dependencies=_auth)
54
+ app.include_router(ridge_regression_router, dependencies=_auth)
55
  app.include_router(cnn_router, dependencies=_auth)
56
  app.include_router(iris_router, dependencies=_auth)
57
  app.include_router(nlp_collaborative_filter_router, dependencies=_auth)
ml/ML_RidgeRegression_HousePricePredictor.ipynb ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "metadata": {},
7
+ "outputs": [
8
+ {
9
+ "name": "stdout",
10
+ "output_type": "stream",
11
+ "text": [
12
+ " square_feet bedrooms bathrooms age_years distance_to_center_km \\\n",
13
+ "0 3574 3 1 21 5.4 \n",
14
+ "1 3907 2 3 20 7.6 \n",
15
+ "2 1260 3 2 5 25.1 \n",
16
+ "3 1694 3 3 0 17.5 \n",
17
+ "4 1530 4 3 4 26.5 \n",
18
+ "\n",
19
+ " price_thousands \n",
20
+ "0 736.19 \n",
21
+ "1 729.73 \n",
22
+ "2 169.12 \n",
23
+ "3 353.68 \n",
24
+ "4 297.71 \n",
25
+ "\n",
26
+ "Price range: $-40.7k – $854.1k\n",
27
+ "\n",
28
+ "R² score : 0.9870\n",
29
+ "RMSE : $22.48k\n",
30
+ "\n",
31
+ "Sample house (1800 sqft, 3 bed, 2 bath, 15 yrs, 8 km): $419.2k\n"
32
+ ]
33
+ }
34
+ ],
35
+ "source": [
36
+ "import numpy as np\n",
37
+ "import pandas as pd\n",
38
+ "from sklearn.linear_model import Ridge\n",
39
+ "from sklearn.preprocessing import StandardScaler\n",
40
+ "from sklearn.pipeline import Pipeline\n",
41
+ "from sklearn.model_selection import train_test_split\n",
42
+ "from sklearn.metrics import mean_squared_error, r2_score\n",
43
+ "\n",
44
+ "np.random.seed(42)\n",
45
+ "n = 300\n",
46
+ "\n",
47
+ "square_feet = np.random.randint(400, 4000, n)\n",
48
+ "bedrooms = np.random.randint(1, 6, n)\n",
49
+ "bathrooms = np.random.randint(1, 4, n)\n",
50
+ "age_years = np.random.randint(0, 60, n)\n",
51
+ "distance_to_center_km = np.round(np.random.uniform(0.5, 35.0, n), 1)\n",
52
+ "\n",
53
+ "# Price formula: size and rooms drive price up, age and distance drive it down\n",
54
+ "price_thousands = (\n",
55
+ " 0.18 * square_feet\n",
56
+ " + 18 * bedrooms\n",
57
+ " + 12 * bathrooms\n",
58
+ " - 1.2 * age_years\n",
59
+ " - 6.5 * distance_to_center_km\n",
60
+ " + np.random.normal(0, 25, n)\n",
61
+ " + 80\n",
62
+ ").round(2)\n",
63
+ "\n",
64
+ "df = pd.DataFrame({\n",
65
+ " 'square_feet': square_feet,\n",
66
+ " 'bedrooms': bedrooms,\n",
67
+ " 'bathrooms': bathrooms,\n",
68
+ " 'age_years': age_years,\n",
69
+ " 'distance_to_center_km': distance_to_center_km,\n",
70
+ " 'price_thousands': price_thousands\n",
71
+ "})\n",
72
+ "\n",
73
+ "print(df.head())\n",
74
+ "print(f'\\nPrice range: ${df.price_thousands.min():.1f}k – ${df.price_thousands.max():.1f}k')\n",
75
+ "\n",
76
+ "X = df[['square_feet', 'bedrooms', 'bathrooms', 'age_years', 'distance_to_center_km']]\n",
77
+ "y = df['price_thousands']\n",
78
+ "\n",
79
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n",
80
+ "\n",
81
+ "# Ridge Regression with StandardScaler in a Pipeline\n",
82
+ "pipeline = Pipeline([\n",
83
+ " ('scaler', StandardScaler()),\n",
84
+ " ('ridge', Ridge(alpha=1.0))\n",
85
+ "])\n",
86
+ "pipeline.fit(X_train, y_train)\n",
87
+ "\n",
88
+ "y_pred = pipeline.predict(X_test)\n",
89
+ "r2 = r2_score(y_test, y_pred)\n",
90
+ "mse = mean_squared_error(y_test, y_pred)\n",
91
+ "rmse = np.sqrt(mse)\n",
92
+ "\n",
93
+ "print(f'\\nR\\u00b2 score : {r2:.4f}')\n",
94
+ "print(f'RMSE : ${rmse:.2f}k')\n",
95
+ "\n",
96
+ "# Sample prediction\n",
97
+ "sample = pd.DataFrame(\n",
98
+ " [[1800, 3, 2, 15, 8.0]],\n",
99
+ " columns=['square_feet', 'bedrooms', 'bathrooms', 'age_years', 'distance_to_center_km']\n",
100
+ ")\n",
101
+ "pred = pipeline.predict(sample)[0]\n",
102
+ "print(f'\\nSample house (1800 sqft, 3 bed, 2 bath, 15 yrs, 8 km): ${pred:.1f}k')"
103
+ ]
104
+ },
105
+ {
106
+ "cell_type": "code",
107
+ "execution_count": 2,
108
+ "metadata": {},
109
+ "outputs": [
110
+ {
111
+ "name": "stderr",
112
+ "output_type": "stream",
113
+ "text": [
114
+ "/usr/local/lib/python3.12/dist-packages/huggingface_hub/utils/_auth.py:122: UserWarning: \n",
115
+ "Error while fetching `HF_TOKEN` secret value from your vault: 'Requesting secret HF_TOKEN timed out. Secrets can only be fetched when running from the Colab UI.'.\n",
116
+ "You are not authenticated with the Hugging Face Hub in this notebook.\n",
117
+ "If the error persists, please let us know by opening an issue on GitHub (https://github.com/huggingface/huggingface_hub/issues/new).\n",
118
+ " warnings.warn(\n"
119
+ ]
120
+ },
121
+ {
122
+ "data": {
123
+ "application/vnd.jupyter.widget-view+json": {
124
+ "model_id": "f8b5064bfed74a1ea1fc53a6a3c93bcc",
125
+ "version_major": 2,
126
+ "version_minor": 0
127
+ },
128
+ "text/plain": [
129
+ "VBox(children=(HTML(value='<center> <img\\nsrc=https://huggingface.co/front/assets/huggingface_logo-noborder.sv…"
130
+ ]
131
+ },
132
+ "metadata": {},
133
+ "output_type": "display_data"
134
+ }
135
+ ],
136
+ "source": [
137
+ "from huggingface_hub import notebook_login\n",
138
+ "\n",
139
+ "notebook_login()"
140
+ ]
141
+ },
142
+ {
143
+ "cell_type": "code",
144
+ "execution_count": 4,
145
+ "metadata": {},
146
+ "outputs": [
147
+ {
148
+ "name": "stdout",
149
+ "output_type": "stream",
150
+ "text": [
151
+ "Model saved locally: /content/ML_RidgeRegression_HousePricePredictor.joblib\n"
152
+ ]
153
+ },
154
+ {
155
+ "data": {
156
+ "application/vnd.jupyter.widget-view+json": {
157
+ "model_id": "a41c535e27f14258a2c9574e8bedde2b",
158
+ "version_major": 2,
159
+ "version_minor": 0
160
+ },
161
+ "text/plain": [
162
+ "Processing Files (0 / 0) : | | 0.00B / 0.00B "
163
+ ]
164
+ },
165
+ "metadata": {},
166
+ "output_type": "display_data"
167
+ },
168
+ {
169
+ "data": {
170
+ "application/vnd.jupyter.widget-view+json": {
171
+ "model_id": "8b8a652bd8eb44ac8c78ac314c382a42",
172
+ "version_major": 2,
173
+ "version_minor": 0
174
+ },
175
+ "text/plain": [
176
+ "New Data Upload : | | 0.00B / 0.00B "
177
+ ]
178
+ },
179
+ "metadata": {},
180
+ "output_type": "display_data"
181
+ },
182
+ {
183
+ "data": {
184
+ "application/vnd.jupyter.widget-view+json": {
185
+ "model_id": "359430ce0d1f45309838e54d501de33e",
186
+ "version_major": 2,
187
+ "version_minor": 0
188
+ },
189
+ "text/plain": [
190
+ " ...ousePricePredictor.joblib: 100%|##########| 1.50kB / 1.50kB "
191
+ ]
192
+ },
193
+ "metadata": {},
194
+ "output_type": "display_data"
195
+ },
196
+ {
197
+ "name": "stdout",
198
+ "output_type": "stream",
199
+ "text": [
200
+ "Uploaded model to https://huggingface.co/looh2/model\n"
201
+ ]
202
+ }
203
+ ],
204
+ "source": [
205
+ "import joblib\n",
206
+ "from pathlib import Path\n",
207
+ "from huggingface_hub import HfApi\n",
208
+ "\n",
209
+ "repo_id = \"looh2/model\"\n",
210
+ "model_path = Path(\"ML_RidgeRegression_HousePricePredictor.joblib\")\n",
211
+ "\n",
212
+ "# Save the pipeline (scaler + Ridge model)\n",
213
+ "joblib.dump(pipeline, model_path)\n",
214
+ "print(f\"Model saved locally: {model_path.resolve()}\")\n",
215
+ "\n",
216
+ "api = HfApi()\n",
217
+ "api.create_repo(repo_id=repo_id, repo_type=\"model\", exist_ok=True)\n",
218
+ "api.upload_file(\n",
219
+ " path_or_fileobj=str(model_path),\n",
220
+ " path_in_repo=model_path.name,\n",
221
+ " repo_id=repo_id,\n",
222
+ " repo_type=\"model\",\n",
223
+ ")\n",
224
+ "print(f\"Uploaded model to https://huggingface.co/{repo_id}\")"
225
+ ]
226
+ },
227
+ {
228
+ "cell_type": "code",
229
+ "execution_count": null,
230
+ "metadata": {},
231
+ "outputs": [],
232
+ "source": [
233
+ "# FastAPI integration reference\n",
234
+ "from fastapi import FastAPI\n",
235
+ "from pydantic import BaseModel\n",
236
+ "import joblib\n",
237
+ "import pandas as pd\n",
238
+ "from huggingface_hub import hf_hub_download\n",
239
+ "\n",
240
+ "model_path = hf_hub_download(\n",
241
+ " repo_id=\"looh2/model\",\n",
242
+ " filename=\"ML_RidgeRegression_HousePricePredictor.joblib\",\n",
243
+ " repo_type=\"model\"\n",
244
+ ")\n",
245
+ "pipeline = joblib.load(model_path)\n",
246
+ "\n",
247
+ "app = FastAPI()\n",
248
+ "\n",
249
+ "class HouseFeatures(BaseModel):\n",
250
+ " square_feet: int\n",
251
+ " bedrooms: int\n",
252
+ " bathrooms: int\n",
253
+ " age_years: int\n",
254
+ " distance_to_center_km: float\n",
255
+ "\n",
256
+ "@app.post(\"/predict\")\n",
257
+ "def predict_house_price(features: HouseFeatures):\n",
258
+ " input_df = pd.DataFrame(\n",
259
+ " [[features.square_feet, features.bedrooms, features.bathrooms,\n",
260
+ " features.age_years, features.distance_to_center_km]],\n",
261
+ " columns=['square_feet', 'bedrooms', 'bathrooms', 'age_years', 'distance_to_center_km']\n",
262
+ " )\n",
263
+ " pred = pipeline.predict(input_df)[0]\n",
264
+ " return {\n",
265
+ " \"predicted_price_thousands\": round(float(pred), 2),\n",
266
+ " \"predicted_price_formatted\": f\"${round(float(pred), 1)}k\"\n",
267
+ " }"
268
+ ]
269
+ }
270
+ ],
271
+ "metadata": {
272
+ "kernelspec": {
273
+ "display_name": "Python 3 (ipykernel)",
274
+ "language": "python",
275
+ "name": "python3"
276
+ },
277
+ "language_info": {
278
+ "codemirror_mode": {
279
+ "name": "ipython",
280
+ "version": 3
281
+ },
282
+ "file_extension": ".py",
283
+ "mimetype": "text/x-python",
284
+ "name": "python",
285
+ "nbconvert_exporter": "python",
286
+ "pygments_lexer": "ipython3",
287
+ "version": "3.12.13"
288
+ }
289
+ },
290
+ "nbformat": 4,
291
+ "nbformat_minor": 5
292
+ }
routes/ML_RidgeRegression_HousePricePredictor.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from pydantic import BaseModel
3
+ import joblib
4
+ import pandas as pd
5
+ from typing import Optional, Any
6
+
7
+ from .config_huggingface import build_model_url, download_artifact_if_needed
8
+
9
+ router = APIRouter(tags=["Machine Learning"])
10
+
11
+
12
+ class RidgeRegressionRequest(BaseModel):
13
+ square_feet: int = 1800
14
+ bedrooms: int = 3
15
+ bathrooms: int = 2
16
+ age_years: int = 15
17
+ distance_to_center_km: float = 8.0
18
+
19
+
20
+ MODEL_STATE: dict[str, Optional[Any]] = {
21
+ "model": None,
22
+ "error": None,
23
+ }
24
+
25
+ MODEL_URL = build_model_url("ML_RidgeRegression_HousePricePredictor.joblib")
26
+
27
+
28
+ def _ensure_model_loaded() -> None:
29
+ if MODEL_STATE["model"] is not None:
30
+ return
31
+ try:
32
+ model_path = download_artifact_if_needed(MODEL_URL)
33
+ MODEL_STATE["model"] = joblib.load(model_path)
34
+ MODEL_STATE["error"] = None
35
+ except Exception as e:
36
+ MODEL_STATE["error"] = str(e)
37
+ raise
38
+
39
+
40
+ @router.post("/models/ridge_regression", summary="Predict house price with Ridge Regression")
41
+ def predict_ridge_regression(data: RidgeRegressionRequest):
42
+ import traceback
43
+ try:
44
+ _ensure_model_loaded()
45
+ except Exception:
46
+ detail = "Model not loaded."
47
+ if MODEL_STATE["error"]:
48
+ detail = f"Model not loaded: {MODEL_STATE['error']}"
49
+ return {"error": detail, "traceback": traceback.format_exc(), "status": 500}
50
+
51
+ model = MODEL_STATE["model"]
52
+ if model is None:
53
+ return {"error": f"Model is None after loading. Error: {MODEL_STATE['error']}", "status": 500}
54
+
55
+ input_df = pd.DataFrame(
56
+ [[data.square_feet, data.bedrooms, data.bathrooms, data.age_years, data.distance_to_center_km]],
57
+ columns=["square_feet", "bedrooms", "bathrooms", "age_years", "distance_to_center_km"],
58
+ )
59
+
60
+ try:
61
+ pred = model.predict(input_df)[0]
62
+ except Exception as e:
63
+ return {"error": f"Prediction failed: {str(e)}", "traceback": traceback.format_exc(), "status": 500}
64
+
65
+ price = round(float(pred), 2)
66
+ return {
67
+ "predicted_price_thousands": price,
68
+ "predicted_price_formatted": f"${price:.1f}k",
69
+ }