{ "cells": [ { "cell_type": "code", "execution_count": 3, "id": "c0b8d60a", "metadata": { "id": "c0b8d60a" }, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import seaborn as sns\n", "import matplotlib.pyplot as plt\n", "import warnings\n", "warnings.filterwarnings(\"ignore\")\n", "sns.set_style(\"darkgrid\")\n", "sns.set_palette('RdYlGn')\n", "\n", "#model\n", "from sklearn.preprocessing import LabelEncoder,StandardScaler,MinMaxScaler\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.metrics import mean_squared_error, r2_score\n", "from sklearn.ensemble import RandomForestRegressor\n", "from xgboost import XGBRegressor\n", "from sklearn.linear_model import LinearRegression\n", "\n", "import gradio as gr\n", "import joblib" ] }, { "cell_type": "code", "execution_count": 4, "id": "11273e4d", "metadata": { "id": "11273e4d" }, "outputs": [], "source": [ "df = pd.read_csv(\"/content/Nigerian_Car_Prices.csv\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "dffa0dba", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 340 }, "id": "dffa0dba", "outputId": "eb17a45d-8e91-41b5-ddae-0be82f2fe1f6" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " Unnamed: 0 Make Year of manufacture Condition Mileage \\\n", "0 0 Toyota 2007.0 Nigerian Used 166418.0 \n", "1 1 Lexus NaN NaN 138024.0 \n", "2 2 Mercedes-Benz 2008.0 Nigerian Used 376807.0 \n", "3 3 Lexus NaN NaN 213362.0 \n", "4 4 Mercedes-Benz NaN NaN 106199.0 \n", "\n", " Engine Size Fuel Transmission Price Build \n", "0 2400.0 Petrol Automatic 3,120,000 NaN \n", "1 NaN NaN Automatic 5,834,000 NaN \n", "2 3000.0 Petrol Automatic 3,640,000 NaN \n", "3 NaN NaN Automatic 3,594,000 NaN \n", "4 NaN NaN Automatic 8,410,000 NaN " ], "text/html": [ "\n", "
\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Unnamed: 0MakeYear of manufactureConditionMileageEngine SizeFuelTransmissionPriceBuild
00Toyota2007.0Nigerian Used166418.02400.0PetrolAutomatic3,120,000NaN
11LexusNaNNaN138024.0NaNNaNAutomatic5,834,000NaN
22Mercedes-Benz2008.0Nigerian Used376807.03000.0PetrolAutomatic3,640,000NaN
33LexusNaNNaN213362.0NaNNaNAutomatic3,594,000NaN
44Mercedes-BenzNaNNaN106199.0NaNNaNAutomatic8,410,000NaN
\n", "
\n", " \n", " \n", " \n", "\n", " \n", "
\n", "
\n", " " ] }, "metadata": {}, "execution_count": 5 } ], "source": [ "df.head()" ] }, { "cell_type": "code", "execution_count": 6, "id": "30f57450", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "30f57450", "outputId": "462327ca-b494-4cc7-d8d1-aa765e166650" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "RangeIndex: 4095 entries, 0 to 4094\n", "Data columns (total 10 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 Unnamed: 0 4095 non-null int64 \n", " 1 Make 4095 non-null object \n", " 2 Year of manufacture 3617 non-null float64\n", " 3 Condition 3616 non-null object \n", " 4 Mileage 4024 non-null float64\n", " 5 Engine Size 3584 non-null float64\n", " 6 Fuel 3607 non-null object \n", " 7 Transmission 4075 non-null object \n", " 8 Price 4095 non-null object \n", " 9 Build 1127 non-null object \n", "dtypes: float64(3), int64(1), object(6)\n", "memory usage: 320.0+ KB\n" ] } ], "source": [ "df.info()" ] }, { "cell_type": "markdown", "id": "2b138a73", "metadata": { "id": "2b138a73" }, "source": [ "### Data Cleaning" ] }, { "cell_type": "code", "execution_count": 7, "id": "fd78bcc0", "metadata": { "id": "fd78bcc0" }, "outputs": [], "source": [ "df = df.drop('Build', axis = 1)" ] }, { "cell_type": "code", "execution_count": 8, "id": "60013f82", "metadata": { "id": "60013f82" }, "outputs": [], "source": [ "df = df.dropna()" ] }, { "cell_type": "code", "execution_count": 9, "id": "62b833d4", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "62b833d4", "outputId": "05f88dbc-c2db-45be-c1c1-0f8553706eae" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "(3523, 9)" ] }, "metadata": {}, "execution_count": 9 } ], "source": [ "df.shape" ] }, { "cell_type": "code", "execution_count": 10, "id": "e04b4172", "metadata": { "id": "e04b4172" }, "outputs": [], "source": [ "df['Price'] = df['Price'].str.replace(',', '') \n", "df['Price'] = df['Price'].astype(float) \n", "\n", "df['Year of manufacture'] = df['Year of manufacture'].astype(int) " ] }, { "cell_type": "code", "execution_count": 11, "id": "c62daca5", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 300 }, "id": "c62daca5", "outputId": "6639a400-6ded-4f42-cbe5-4469c7fa27f2" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " Unnamed: 0 Year of manufacture Mileage Engine Size \\\n", "count 3523.000000 3523.000000 3.523000e+03 3523.000000 \n", "mean 2089.276753 2007.921090 1.901794e+05 3170.591541 \n", "std 1187.608368 4.303771 2.215162e+05 4641.379934 \n", "min 0.000000 1992.000000 1.000000e+00 3.000000 \n", "25% 1066.500000 2005.000000 1.070360e+05 2000.000000 \n", "50% 2085.000000 2008.000000 1.670060e+05 2500.000000 \n", "75% 3136.500000 2011.000000 2.397715e+05 3500.000000 \n", "max 4094.000000 2021.000000 9.976050e+06 184421.000000 \n", "\n", " Price \n", "count 3.523000e+03 \n", "mean 4.060590e+06 \n", "std 4.520306e+06 \n", "min 4.725000e+05 \n", "25% 1.800000e+06 \n", "50% 2.835000e+06 \n", "75% 4.500000e+06 \n", "max 5.880000e+07 " ], "text/html": [ "\n", "
\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Unnamed: 0Year of manufactureMileageEngine SizePrice
count3523.0000003523.0000003.523000e+033523.0000003.523000e+03
mean2089.2767532007.9210901.901794e+053170.5915414.060590e+06
std1187.6083684.3037712.215162e+054641.3799344.520306e+06
min0.0000001992.0000001.000000e+003.0000004.725000e+05
25%1066.5000002005.0000001.070360e+052000.0000001.800000e+06
50%2085.0000002008.0000001.670060e+052500.0000002.835000e+06
75%3136.5000002011.0000002.397715e+053500.0000004.500000e+06
max4094.0000002021.0000009.976050e+06184421.0000005.880000e+07
\n", "
\n", " \n", " \n", " \n", "\n", " \n", "
\n", "
\n", " " ] }, "metadata": {}, "execution_count": 11 } ], "source": [ "df.describe()" ] }, { "cell_type": "markdown", "id": "910be70f", "metadata": { "id": "910be70f" }, "source": [ "### EDA" ] }, { "cell_type": "markdown", "id": "90e49305", "metadata": { "id": "90e49305" }, "source": [ "### Feature Engineering" ] }, { "cell_type": "code", "source": [ "#the brand new is just 5, it will be drop\n", "# Dropping the 'Brand New' category\n", "df = df[df['Condition'] != 'Brand New']" ], "metadata": { "id": "PkF02_5ah3bB" }, "id": "PkF02_5ah3bB", "execution_count": 35, "outputs": [] }, { "cell_type": "code", "execution_count": 38, "id": "544f2b81", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "544f2b81", "outputId": "efdf1889-b1b6-445c-901a-acab17d1cda1" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "['scaler.joblib']" ] }, "metadata": {}, "execution_count": 38 } ], "source": [ "X = df.drop(['Unnamed: 0', 'Price'], axis = 1)\n", "y = df.Price\n", "\n", "make_counts = X['Make'].value_counts()\n", "\n", "\n", "# Get the values to replace with 'Others'\n", "make_others = make_counts[make_counts < 14].index.tolist()\n", "\n", "# Replace values with 'Others'\n", "X['Make'] = X['Make'].apply(lambda x: 'Others' if x in make_others else x)\n", "\n", "X_train,X_test, y_train,y_test = train_test_split(X,y, test_size = 0.2, random_state=10)\n", "\n", "\n", "# Initializing the encoders and scaler for each column\n", "make_encoder = LabelEncoder()\n", "fuel_encoder = LabelEncoder()\n", "transmission_encoder = LabelEncoder()\n", "condition_encoder = LabelEncoder()\n", "scaler = MinMaxScaler()\n", "\n", "# Encoding and scaling each column individually\n", "X_train['Make'] = make_encoder.fit_transform(X_train['Make'])\n", "X_test['Make'] = make_encoder.transform(X_test['Make'])\n", "\n", "X_train['Fuel'] = fuel_encoder.fit_transform(X_train['Fuel'])\n", "X_test['Fuel'] = fuel_encoder.transform(X_test['Fuel'])\n", "\n", "X_train['Transmission'] = transmission_encoder.fit_transform(X_train['Transmission'])\n", "X_test['Transmission'] = transmission_encoder.transform(X_test['Transmission'])\n", "\n", "X_train['Condition'] = condition_encoder.fit_transform(X_train['Condition'])\n", "X_test['Condition'] = condition_encoder.transform(X_test['Condition'])\n", "\n", "X_train[['Year of manufacture', 'Mileage', 'Engine Size']] = scaler.fit_transform(X_train[['Year of manufacture', 'Mileage', 'Engine Size']])\n", "X_test[['Year of manufacture', 'Mileage', 'Engine Size']] = scaler.transform(X_test[['Year of manufacture', 'Mileage', 'Engine Size']])\n", "\n", "# Save the encoders and scaler\n", "joblib.dump(make_encoder, \"make_encoder.joblib\",compress=3)\n", "joblib.dump(fuel_encoder, \"fuel_encoder.joblib\",compress=3)\n", "joblib.dump(transmission_encoder, \"transmission_encoder.joblib\",compress=3)\n", "joblib.dump(condition_encoder, \"condition_encoder.joblib\",compress=3)\n", "joblib.dump(scaler, \"scaler.joblib\",compress=3)" ] }, { "cell_type": "markdown", "id": "307eab41", "metadata": { "id": "307eab41" }, "source": [ "#### Needed Model" ] }, { "cell_type": "code", "execution_count": 39, "id": "23aaa0f7", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "23aaa0f7", "outputId": "7ac3f946-76f2-4e32-bda3-84106fcec209" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Random Forest RMSE: 1900923.15\n", "XGBoost RMSE: 1881430.11\n", "Linear Regression RMSE: 3227815.24\n" ] } ], "source": [ "# Initialize the models\n", "rf_model = RandomForestRegressor(random_state=42)\n", "xgb_model = XGBRegressor(random_state=42)\n", "lr_model = LinearRegression()\n", "\n", "# Fit the models on the training data\n", "rf_model.fit(X_train, y_train)\n", "xgb_model.fit(X_train, y_train)\n", "lr_model.fit(X_train, y_train)\n", "\n", "# Make predictions on the testing data\n", "rf_preds = rf_model.predict(X_test)\n", "xgb_preds = xgb_model.predict(X_test)\n", "lr_preds = lr_model.predict(X_test)\n", "\n", "# Evaluate the models using root mean squared error (RMSE)\n", "rf_rmse = mean_squared_error(y_test, rf_preds, squared=False)\n", "xgb_rmse = mean_squared_error(y_test, xgb_preds, squared=False)\n", "lr_rmse = mean_squared_error(y_test, lr_preds, squared=False)\n", "\n", "# Print the RMSE scores\n", "print(f\"Random Forest RMSE: {rf_rmse:.2f}\")\n", "print(f\"XGBoost RMSE: {xgb_rmse:.2f}\")\n", "print(f\"Linear Regression RMSE: {lr_rmse:.2f}\")" ] }, { "cell_type": "code", "source": [ "# R2 score\n", "rf_r2 = r2_score(y_test, rf_preds)\n", "print(\"Random Forest R2 Score:\", rf_r2)\n", "\n", "\n", "xgb_r2 = r2_score(y_test, xgb_preds)\n", "print(\"XGBoost R2 Score:\", xgb_r2)\n", "\n", "\n", "lr_r2 = r2_score(y_test, lr_preds)\n", "print(\"Linear Regression R2 Score:\", lr_r2)\n" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "HAij8ecNkQf4", "outputId": "cfeb36b4-201b-413a-8b4f-ce722b9d7ef3" }, "id": "HAij8ecNkQf4", "execution_count": 40, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Random Forest R2 Score: 0.7692007346747749\n", "XGBoost R2 Score: 0.7739099336774033\n", "Linear Regression R2 Score: 0.33453895627915986\n" ] } ] }, { "cell_type": "code", "execution_count": 41, "id": "f9dfda36", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "f9dfda36", "outputId": "69882d26-6915-4f06-c5af-d38ce97417cd" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "['car_model.joblib']" ] }, "metadata": {}, "execution_count": 41 } ], "source": [ "joblib.dump(xgb_model, \"car_model.joblib\", compress=3)" ] }, { "cell_type": "markdown", "id": "faeff4c7", "metadata": { "id": "faeff4c7" }, "source": [ "**Note: Many Models have been built, but only the needed ones were kept**" ] }, { "cell_type": "code", "execution_count": 42, "id": "1b6ca9be", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 472 }, "id": "1b6ca9be", "outputId": "a049c64e-ea4f-44d3-9bfb-4a03cc01a7cf" }, "outputs": [ { "output_type": "display_data", "data": { "text/plain": [ "
" ], "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHHCAYAAABZbpmkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABMyUlEQVR4nO3de3zP9f//8dvrfdjmMMOcGzOnqWaaDjJKVJ8Kq9DJp1BJKPGh+oZ8nFKkA0JIJVF8lPr8Qh99dFB9spRScow252LmNLPje6/fH7M3bzPznvf2fu/lfr1cduH9Ojxfj/fzPdvd6/l6vl6GaZomIiIiIhZl83cBIiIiIqVJYUdEREQsTWFHRERELE1hR0RERCxNYUdEREQsTWFHRERELE1hR0RERCxNYUdEREQsTWFHRERELE1hR0TOqWPHjgwbNsz9es2aNURHR7NmzRqfHSM6Oppp06b5rD3xnZ49e9KzZ09/lyFyQRR2RALYRx99RHR0tPurRYsW3HLLLYwbN46DBw/6uzyvfP311wEVaBISErjhhhs41xNz7rvvPuLj48nNzfXJMf/44w/353js2LEStzNr1iw+//xzn9QkcjFQ2BEpBwYNGsSkSZMYNWoUcXFxLFy4kHvvvZeMjIwyr+Xqq69m/fr1XH311V7t9/XXXzN9+vSzrlu/fj0DBgzwRXnnLSEhgT///JO1a9eedf2ePXv45Zdf6NSpEw6HwyfH/OSTT6hZsyYAn332WYnbmT17tsKOiBcUdkTKgeuvv5477riDu+++m4kTJ9K7d2/27NnDF198UeQ+J06cKJVabDYbwcHB2Gy++/ERHBzss0BxvhISEjAMg6VLl551/fLlyzFNk4SEBJ8czzRNli5dSpcuXWjfvj2ffPKJT9oVkeIp7IiUQ9deey2Qf/YBYNiwYcTFxbFr1y769u1LXFwcTz31FAB5eXm88847dO7cmRYtWhAfH8+oUaM4evSoR5umafL6669z/fXX07JlS3r27Mm2bdsKHbuoa3Z+/fVX+vbty9VXX80VV1xBQkIC8+bNc9f33nvvAXgMyxU42zU7mzZt4pFHHqFVq1bExcXRu3dvfvnlF49tCob5fvrpJyZMmMC1117LFVdcweOPP86hQ4fO2Yd169bl6quv5rPPPiMnJ6fQ+mXLltGgQQNatmzpXjZ//nw6d+5My5Ytufrqq+nWrVuRYelMP/30E3v37qVTp0506tSJtWvX8tdffxXaLi8vj3nz5pGQkECLFi249tpr6dOnD7/99pu7r06cOMHHH3/s7seCa6qGDRtGx44dC7U5bdo0j/4GWLJkCb169aJNmzbExMTQqVMn3n///fN6LyLlTdn+V0pEfGLXrl0AVK1a1b0sNzeXPn36cOWVV/LMM88QEhICwKhRo/j444/p1q0bPXv2ZM+ePbz33nts2rSJhQsX4nQ6AZg6dSozZ86kffv2tG/fno0bN/Lwww+fNQic6bvvvqNfv37UqlWLXr16UaNGDf744w9WrVpF7969uffeezlw4ADfffcdkyZNKra9bdu2cf/991OpUiUeeeQRHA4H//rXv+jZsycLFizwCCAA48ePp0qVKgwcOJC9e/cyb948xo0bx5QpU855nISEBP75z3/yv//9jw4dOriXb926ld9//53HH3/cvWzx4sWMHz+eW265hV69epGVlcXWrVv59ddfz+vsz9KlS2nQoAGxsbE0a9aMkJAQli1bxiOPPOKx3bPPPstHH33E9ddfz1133YXL5WLt2rX8+uuvtGjRgkmTJjFy5EhiY2O55557AGjQoEGxxz/TwoULadq0KR07dsThcPDVV18xduxYTNPk/vvv97o9kUCmsCNSDhw/fpxDhw6RnZ3Nzz//zIwZMwgJCfH4BZ2dnc2tt97Kk08+6V62du1aPvjgA15++WWPX8itW7fmkUceYcWKFSQkJHDo0CHefPNNbrjhBmbNmoVhGABMnjyZWbNmnbM2l8vFqFGjqFWrFv/+97+pUqWKe13Bxb9xcXE0bNiQ7777jjvuuKPY9ztlyhRycnJYuHAh9evXB+DOO+/k1ltv5aWXXmLBggUe21etWpW3337bXXdeXh7z588nLS2N0NDQIo9zyy238Nxzz7Fs2TKPvly2bBmAR5+tWrWKpk2b8tprrxVb/5lycnJYsWIF9913HwAhISF07NiRpUuXeoSd77//no8++oiePXsycuRI9/KHH37Y3Zd33HEHY8aMoX79+ufVl0VZsGCBOxADPPDAA/Tp04e5c+cq7IjlaBhLpBx48MEHadOmDe3bt2fIkCFUqlSJ6dOnU7t2bY/tevTo4fF6xYoVhIaG0rZtWw4dOuT+uvzyy6lYsaJ7KGr16tXk5OTwwAMPuAMDQO/evYutbdOmTezZs4devXp5BB3Ao63z5XK5+O6777jpppvcQQegVq1adOnShZ9++onjx4977HPPPfd4HOuqq67C5XKxd+/ecx4rLCyM9u3b8+WXX7qvcTJNk+XLlxMTE0NUVJR72ypVqvDXX3+xfv16r9/TN998w5EjR+jSpYt7WZcuXdiyZYvHUOF///tfDMNg4MCBhdooSV+ey+lBJy0tjUOHDnHNNdewe/du0tLSfHosEX/TmR2RcmDUqFFERUVht9upUaMGUVFRhS4Qdjgc1KlTx2PZzp07SUtLo02bNmdtNzU1FYB9+/YB0LBhQ4/11atXJyws7Jy17d69G4BmzZqd9/s5l0OHDpGRkeERNAo0btyYvLw8/vzzT5o2bepeXq9ePY/tCkLX+UzvTkhIYOXKlXzxxRckJCTw888/s3fvXnr16uWxXd++fVm9ejV33303kZGRtG3bli5dunDllVcWe4xPPvmEiIgIgoKC2LlzJ5A/9FShQgWWLl3K0KFDgfzhyVq1ankMT5aWn376iWnTpvHLL78UmtVX3BkxkfJGYUekHIiNjaVFixbn3CYoKKhQAMrLyyM8PJyXX375rPtUr17dZzX6U1Ezw851D50CHTp0IDQ0lGXLlpGQkMCyZcuw2+107tzZY7vGjRuzYsUKVq1axbfffst///tf3n//fR5//HEGDRpUZPvHjx/nq6++Iisri7/97W+F1i9btowhQ4b45MxNUW24XC6P17t27eLBBx+kUaNGDBs2jLp16+J0Ovn666955513yMvLu+BaRAKJwo6IhTVo0IDExERatWrlMWxxpoIzIzt27PAYOjp06FChWVtnKtj+999/Jz4+vsjtzveXefXq1alQoQLJycmF1iUlJWGz2ahbt+55tXU+goKCuOWWW/h//+//cfDgQVasWMG1117rvh/O6SpWrOieTZWdnc0TTzzBrFmz6NevH8HBwWdt/7///S9ZWVmMGTOGatWqeaxLTk5mypQp/PTTT1x11VU0aNCA//3vfxw5cqREZ3eqVKly1rNZBWfuCnz55ZdkZ2czc+ZMj7Nivrwrtkgg0TU7IhZ222234XK5eP311wuty83Ndf9ijI+Px+l0smDBAo+zIQVTx8/l8ssvJyIignfffbfQL9rT26pQoQJQ/NCS3W6nbdu2fPHFF+6p9QAHDx5k2bJlXHnllVSuXLnYuryR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k549e9KiRQs6d+7M2rVrS6tWEREREa95FXbmzZvHPffcQ+XKlQutCw0N5d5772Xu3Lk+K05ERETkQnkVdrZu3cp1111X5Pq2bduycePGCy5KRERExFe8CjsHDx7E4Sj6Mh+Hw8GhQ4cuuCgRERERX/Eq7NSuXZtt27YVuX7r1q3UrFnzgosSERER8RWvwk779u2ZOnUqWVlZhdZlZmYybdo0OnTo4LPiRERERC6UV1PPBwwYwH//+19uueUW7r//fqKiogBISkri/fffx+Vy0b9//1IpVERERKQkvAo7NWrUYNGiRYwZM4ZXX30V0zQBMAyDdu3aMWrUKGrUqFEqhYqIiIiUhNc3FbzkkkuYM2cOR48eZefOnQBERkYSFhbm8+JERERELlSJ7qAMEBYWRmxsrC9rEREREfG5Ej0IVERERKS8UNgRERERS1PYEREREUtT2BERERFLU9gRERERS1PYEREREUtT2BERERFLU9gRERERS1PYEREREUtT2BERERFLU9gRERERS1PYEREREUtT2BERERFLU9gRERERS1PYEREREUtT2BERERFLU9gRERERS1PYEREREUtT2BERERFLc/i7gIuJw3EqW9rtypkiIiJlQWGnjDgcNmbPDiE52QSgbVvDzxWJiIhcHBR2ylByssnGjfl/j4oyAQUeERGR0lauxlLeeOMNoqOjef75593LsrKyGDt2LK1btyYuLo4nnniCgwcP+rFKERERCSTlJuysX7+eRYsWER0d7bH8hRde4KuvvmLKlCnMnz+fAwcOMHDgQD9VKSIiIoGmXISd9PR0nn76acaPH09YWJh7eVpaGkuWLGHYsGG0adOGmJgYXnjhBdatW8cvv/ziv4JFREQkYJSLa3bGjRtH+/btiY+PZ+bMme7lGzZsICcnh/j4ePeyxo0bU69ePX755ReuuOIKr45j+PASmoK2zvzTnwwjMOooSiD1VXmhPvOe+sx76jPvqL+8V9I+O9/tAz7sLF++nE2bNvHhhx8WWnfw4EGcTidVqlTxWB4eHk5KSorXxwoPDy1xnefTpt0OTmf+3222/NcOB/mflu3kFwbGuV4bRv6H68U+zpPT3KtWreTz91caSuNzsDr1mffUZ95Tn3lH/eW90uqzgA47f/75J88//zxvv/02wcHBpX681NQ0TNM3bRlG/odW0KbDYcPlCiYnJ399Xh64XAa5uWA3Tcg7+YWJea7XJvk1erFPjisPTJP0I+nk5ub55g2WgjP7TIqnPvOe+sx76jPvqL+8V9I+K9ivOAEddjZu3EhqairdunVzL3O5XPz444+89957vPXWW+Tk5HDs2DGPszupqanUrFnT6+OZBUHChwraDIRv+ECpozjlpc5Aoj7znvrMe+oz76i/vFdafRbQYefaa69l6dKlHsuGDx9Oo0aN6Nu3L3Xr1sXpdJKYmMgtt9wCQFJSEvv27fP6ep2yYpw2wBjo19CIiIhYQUCHncqVK9OsWTOPZRUrVqRq1aru5d27d2fixImEhYVRuXJlxo8fT1xcXICGHQP73j2QmYktpQq2A2BLUdoREREpTQEdds7HiBEjsNlsDBo0iOzsbNq1a8fo0aP9XVbRMjMhPR2ygiHbgCx/FyQiImJt5S7szJ8/3+N1cHAwo0ePDuyAIyIiIn5TLm4qKCIiIlJSCjsiIiJiaQo7IiIiYmkKOyIiImJpCjsiIiJiaQo7IiIiYmkKOyIiImJpCjsiIiJiaQo7IiIiYmnl7g7K4h2H08CIigLTxG4/lW1zc/P8WJWIiEjZUdixuIgmwUw+2JvkLVm4dgQBJlFRBv36ZSrwiIjIRUFh5yKQvCWLTT9n4joKpglg+rskERGRMqNrdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHZERETE0hR2RERExNIUdkRERMTSFHYuFoaBYYBhGICB3a6PXkRELg76jXexCA7GtncP9j+2Y9+7h4off4jDoY9fRESsz+HvAqQMZWRCejpkmLBvr7+rERERKRMKOxchh9OAevU8hrJyc/P8WJGIiEjpUdi5CEU0CWby5s5sXx0EmERFGfTrl6nAIyIilqSwc5FK/j2bTSlgmgCmv8sREREpNbpCVURERCxNYUdEREQsTWFHRERELE1hR0RERCxNFygLDgfY7TaPqeguV/7MLM3QEhGR8k5hR6hfH2bODGbn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Fa1ateLee+/l66+/9ndZ5cobb7xBdHQ0zz//vL9LCVjTpk0jOjra4+vWW2/1d1kBb//+/Tz11FO0bt2a2NhYEhIS+O2333x6DEvcZyeQfPrpp0yYMIGxY8fSsmVL5s2bR58+fVixYkWhh5VKvhMnThAdHU337t0ZOHCgv8sJeD/88AP3338/LVq0wOVy8eqrr9KnTx+WL19OxYoV/V1eQKpTpw5PPfUUkZGRmKbJv//9bx5//HE+/vhjmjZt6u/yAt769etZtGgR0ac/VFTOqmnTpsydO9f92m63+7GawHf06FF69OhB69atmTNnDtWqVWPnzp2EhYX59DgKOz42d+5c7rnnHrp37w7A2LFjWbVqFUuWLOHRRx/1c3WBqX379rRv397fZZQbb731lsfriRMn0qZNGzZu3MjVV1/tp6oCW8eOHT1eDxkyhIULF/LLL78o7BQjPT2dp59+mvHjxzNz5kx/lxPw7HY7NWvW9HcZ5cacOXOoU6cOEyZMcC+rX7++z4+jYSwfys7OZuPGjcTHx7uX2Ww24uPjWbdunR8rEytLS0sD8Pn/hKzK5XKxfPlyTpw4oefnnYdx48bRvn17j59rUrSdO3fSrl07brzxRp588kn27dvn75IC2pdffklMTAyDBg2iTZs23HnnnSxevNjnx9GZHR86fPgwLper0HBVeHi4rqmQUpGXl8cLL7xAq1ataNasmb/LCWhbt27lvvvuIysri4oVKzJjxgyaNGni77IC2vLly9m0aRMffvihv0spF2JjY5kwYQJRUVGkpKQwY8YM7r//fpYuXUrlypX9XV5A2r17NwsXLuShhx6if//+/Pbbb4wfPx6n00nXrl19dhyFHZFybOzYsWzbto3333/f36UEvKioKP7973+TlpbGZ599xjPPPMOCBQsUeIrw559/8vzzz/P2228THBzs73LKhdOH45s3b07Lli3p0KED//nPf7j77rv9WFngMk2TmJgYhg4dCsBll13Gtm3bWLRokcJOoKpWrRp2u53U1FSP5ampqXooqfjcuHHjWLVqFQsWLKBOnTr+LifgBQUFERkZCUBMTAy//fYb7777LuPGjfNzZYFp48aNpKam0q1bN/cyl8vFjz/+yHvvvcdvv/2mi2+LUaVKFRo2bMiuXbv8XUrAqlmzJo0bN/ZY1qhRIz777DOfHkdhx4eCgoK4/PLLSUxM5KabbgLyhxkSExN54IEH/FydWIVpmjz33HOsXLmS+fPnl8rFfBeDvLw8srOz/V1GwLr22mtZunSpx7Lhw4fTqFEj+vbtq6BzHtLT09m9e7cuWD6HVq1akZyc7LFsx44dXHLJJT49jsKOjz300EM888wzxMTEEBsby7x588jIyPD435F4Sk9P9/ifz549e9i8eTNhYWHUq1fPj5UFprFjx7Js2TJef/11KlWqREpKCgChoaGEhIT4ubrA9Morr3D99ddTt25d0tPTWbZsGT/88EOhmW1ySuXKlQtdB1axYkWqVq2q68OK8OKLL9KhQwfq1avHgQMHmDZtGjabjS5duvi7tIDVu3dvevTowaxZs7jttttYv349ixcv9vkZV8M0TdOnLQoLFizgrbfeIiUlhUsvvZSRI0fSsmVLf5cVsNasWUOvXr0KLe/atSsTJ070Q0WBrah7nUyYMEGhuggjRozg+++/58CBA4SGhhIdHU3fvn1p27atv0srV3r27Enz5s159tln/V1KQBoyZAg//vgjR44coXr16lx55ZUMGTKEBg0a+Lu0gPbVV1/x6quvsmPHDiIiInjooYe45557fHoMhR0RERGxNN1nR0RERCxNYUdEREQsTWFHRERELE1hR0RERCxNYUdEREQsTWFHRERELE1hR0RERCxNYUdELKljx4688847/i5D5KL2448/0r9/f9q1a0d0dDSff/65V/tPmzaN6OjoQl9XXHGFV+3ocREiEvCGDRvGxx9/DIDT6aRu3brccccd9O/fH4fj7D/GPvzwQypUqFCWZYrIGU6cOEF0dDTdu3dn4MCBXu//8MMPc99993kse/DBB2nRooVX7SjsiEi5cN111zFhwgSys7P5+uuvGTduHE6nk379+nlsl52dTVBQENWrV/dTpSJSoH379rRv377I9dnZ2UyePJlly5aRlpZG06ZNeeqpp2jdujUAlSpVolKlSu7tt2zZwvbt2xk7dqxXdSjsiEi5EBQU5H569N///nc+//xzvvzyS5KTkzl27BgtWrTgvffeIygoiC+//JKOHTvSq1cvHnzwQQCOHTvGyy+/zOeff05aWhqRkZE8+eSTdOjQAYC1a9fy6quvsmHDBqpVq8bNN9/M0KFDqVixor/esojljRs3ju3btzN58mRq1arFypUreeSRR1i6dCkNGzYstP0HH3xAw4YNueqqq7w6jsKOiJRLwcHBHDlyBIDExEQqV67M3Llzz7ptXl4effv2JT09nZdeeokGDRqwfft2bLb8yxZ37dpF3759GTx4MC+88AKHDh3iueee47nnnmPChAll9ZZELir79u3jo48+4quvvqJ27doA9OnTh2+//ZaPPvqIoUOHemyflZXF0qVL6du3r9fHUtgRkXLFNE0SExP53//+xwMPPMDhw4epWLEi48ePJygo6Kz7rF69mvXr1/Ppp58SFRUFQP369d3rZ8+eTUJCgvssUMOGDXn22Wfp2bMnY8aMITg4uNTfl8jF5vfff8flcnHrrbd6LM/OzqZq1aqFtl+5ciXp6el07drV62Mp7IhIubBq1Sri4uLIycnBNE26dOnCE088wbhx42jWrFmRQQdg8+bN1KlTxx10zrRlyxa2bt3K0qVL3ctM0yQvL489e/bQuHFjn78fkYvdiRMnsNvtLFmyBLvd7rHubMPHH3zwATfccAM1atTw+lgKOyJSLrRu3ZoxY8bgdDqpVauWxyys4mZdhYSEnHP9iRMnuO++++jZs2ehdXXr1i1ZwSJyTpdeeikul4tDhw4Vew3O7t27WbNmDTNnzizRsRR2RKRcqFChApGRkSXaNzo6mr/++ovk5OSznt257LLL2L59e4nbF5GzS09PZ9euXe7Xe/bsYfPmzYSFhREVFUVCQgL/93//x7Bhw7j00ks5fPgwiYmJREdHc8MNN7j3W7JkCTVr1uT6668vUR0KOyJieddccw1XXXUVgwYNYtiwYTRo0ICkpCQMw+D666+nb9++3HvvvYwbN467776bChUqsH37dlavXs2oUaP8Xb5IubVhwwZ69erlfl1wwX/Xrl2ZOHEiEyZMYObMmUycOJEDBw5QtWpVrrjiCo+gk5eXx8cff0y3bt0KDXedL4UdEbkoTJs2jRdffJGhQ4eSkZHhnnoO0Lx5c+bPn8+UKVP4+9//DuRfwNypUyd/lixS7rVu3ZqtW7cWud7pdDJo0CAGDRpU5DY2m42vv/76guowTNM0L6gFERERkQCmZ2OJiIiIpSnsiIiIiKUp7IiIiIilKeyIiIiIpSnsiIiIiKUp7IiIiIilKeyIiIiIpSnsiIiIiKUp7IiIiIilKeyIiIiIpSnsiIiIiKUp7IiIiIil/X8f88AsiiPMZgAAAABJRU5ErkJggg==\n" }, "metadata": {} } ], "source": [ "sns.histplot(xgb_preds, label='prediction',color='red')\n", "sns.histplot(y_test, label='actual price', color = 'blue')\n", "plt.title('Prediction Vs Actual')\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "e921f047", "metadata": { "id": "e921f047" }, "source": [ "### Prediction" ] }, { "cell_type": "code", "execution_count": 43, "id": "e23ac604", "metadata": { "id": "e23ac604" }, "outputs": [], "source": [ "import joblib\n", "def predict_car_price(make, year, condition, mileage, engine_size, fuel, transmission):\n", " # Load the encoders and scaler\n", " make_encoder = joblib.load(\"make_encoder.joblib\")\n", " fuel_encoder = joblib.load(\"fuel_encoder.joblib\")\n", " transmission_encoder = joblib.load(\"transmission_encoder.joblib\")\n", " condition_encoder = joblib.load(\"condition_encoder.joblib\")\n", " scaler = joblib.load(\"scaler.joblib\")\n", "\n", " # Preprocess the input\n", " make_encoded = make_encoder.transform([make])[0]\n", " numerical_value = scaler.transform([[year,mileage, engine_size]])\n", " year_scaled = numerical_value[0][0]\n", " mileage_scaled = numerical_value[0][1]\n", " engine_size_scaled = numerical_value[0][2]\n", " fuel_encoded = fuel_encoder.transform([fuel])[0]\n", " condition_encoded = condition_encoder.transform([condition])[0]\n", " transmission_encoded = transmission_encoder.transform([transmission])[0]\n", "\n", " input_data = [[make_encoded, year_scaled, condition_encoded, mileage_scaled, engine_size_scaled, fuel_encoded, transmission_encoded]]\n", " input_df = pd.DataFrame(input_data, columns=['Make', 'Year of manufacture', 'Condition', 'Mileage', 'Engine Size', 'Fuel', 'Transmission'])\n", "\n", " # Make predictions\n", " predicted_price = xgb_model.predict(input_df)\n", " return round(predicted_price[0], 2)" ] }, { "cell_type": "code", "execution_count": 44, "id": "07692f2e", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "07692f2e", "outputId": "c70a6f63-72db-4129-e38a-2f319e506f35" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "4970118.0" ] }, "metadata": {}, "execution_count": 44 } ], "source": [ "predict_car_price('Toyota', 2010,'Nigerian Used', 3000, 2300, 'Petrol', 'Automatic')" ] }, { "cell_type": "markdown", "id": "fce6ae74", "metadata": { "id": "fce6ae74" }, "source": [ "### Gradio Interface" ] }, { "cell_type": "code", "source": [ "import gradio as gr\n", "import joblib\n", "def predict_car_price(make, year, condition, mileage, engine_size, fuel, transmission):\n", " # Load the encoders and scaler\n", " make_encoder = joblib.load(\"make_encoder.joblib\")\n", " fuel_encoder = joblib.load(\"fuel_encoder.joblib\")\n", " transmission_encoder = joblib.load(\"transmission_encoder.joblib\")\n", " condition_encoder = joblib.load(\"condition_encoder.joblib\")\n", " scaler = joblib.load(\"scaler.joblib\")\n", "\n", " make_encoded = make_encoder.transform([make])[0]\n", " numerical_value = scaler.transform([[year,mileage, engine_size]])\n", " year_scaled = numerical_value[0][0]\n", " mileage_scaled = numerical_value[0][1]\n", " engine_size_scaled = numerical_value[0][2]\n", " fuel_encoded = fuel_encoder.transform([fuel])[0]\n", " condition_encoded = condition_encoder.transform([condition])[0]\n", " transmission_encoded = transmission_encoder.transform([transmission])[0]\n", " input_data = [[make_encoded, year_scaled, condition_encoded, mileage_scaled, engine_size_scaled, fuel_encoded, transmission_encoded]]\n", " input_df = pd.DataFrame(input_data, columns=['Make', 'Year of manufacture', 'Condition', 'Mileage', 'Engine Size', 'Fuel', 'Transmission'])\n", "\n", " # Make predictions\n", " predicted_price = xgb_model.predict(input_df)\n", " return round(predicted_price[0], 2)\n", "make_dropdown = gr.inputs.Dropdown(['Acura', 'Audi', 'BMW', 'Chevrolet', 'Dodge', 'Ford', 'Honda',\n", " 'Hyundai', 'Infiniti', 'Kia', 'Land Rover', 'Lexus', 'Mazda',\n", " 'Mercedes-Benz', 'Mitsubishi', 'Nissan', 'Peugeot',\n", " 'Pontiac', 'Toyota', 'Volkswagen', 'Volvo'], label=\"Make\")\n", "condition_dropdown = gr.inputs.Dropdown(['Foreign Used', 'Nigerian Used'], label=\"Condition\")\n", "fuel_dropdown = gr.inputs.Dropdown([\"Petrol\", \"Diesel\", \"Electric\"], label=\"Fuel\")\n", "transmission_dropdown = gr.inputs.Dropdown([\"Manual\", \"Automatic\", \"AMT\"], label=\"Transmission\")\n", "year_slider = gr.inputs.Slider(minimum=1992, maximum=2021, step=1, default=2010, label=\"Year\")\n", "mileage_slider = gr.inputs.Slider(minimum=1, maximum=300000, step=10, default=80000, label=\"Mileage\")\n", "engine_size_slider = gr.inputs.Slider(minimum=1, maximum=20000, step=1, default=100, label=\"Engine Size\")\n", "\n", "iface = gr.Interface(\n", "fn=predict_car_price,\n", "inputs=[make_dropdown, year_slider, condition_dropdown, mileage_slider, engine_size_slider, fuel_dropdown, transmission_dropdown],\n", "outputs=\"number\",\n", "title=\"Car Price Prediction\",\n", " description=\"Predict the price of a car based on its details, in Naira.\",\n", " examples=[\n", " [\"Toyota\", 2010, \"Nigerian Used\", 80000, 2.0, \"Petrol\", \"Automatic\"],\n", " [\"Mercedes-Benz\", 2015, \"Foreign Used\", 50000, 1000, \"Diesel\", \"AMT\"],\n", " ],css=\".gradio-container {background-color: lightgreen}\"\n", ")\n", "\n", "iface.launch(share = True)\n" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 611 }, "id": "0ZNR9WJ5m5dA", "outputId": "b4292dcc-3397-46db-d5b2-3932ff51c657" }, "id": "0ZNR9WJ5m5dA", "execution_count": 46, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Colab notebook detected. To show errors in colab notebook, set debug=True in launch()\n", "Running on public URL: https://99918e8c858d7db896.gradio.live\n", "\n", "This share link expires in 72 hours. For free permanent hosting and GPU upgrades, run `gradio deploy` from Terminal to deploy to Spaces (https://huggingface.co/spaces)\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ "" ], "text/html": [ "
" ] }, "metadata": {} }, { "output_type": "execute_result", "data": { "text/plain": [] }, "metadata": {}, "execution_count": 46 } ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" }, "colab": { "provenance": [] } }, "nbformat": 4, "nbformat_minor": 5 }