{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "df16d02a-fc85-4581-a2d5-8ab2d896d918",
   "metadata": {},
   "source": [
    "# Practical-A1 (Uber)\n",
    "\n",
    "---\n",
    "\n",
    "Problem Statement: Predict the price of the Uber ride from a given pickup point to the agreed drop-off location.\n",
    "Perform following tasks:\n",
    "1. Pre-process the dataset.\n",
    "2. Identify outliers.\n",
    "3. Check the correlation.\n",
    "4. Implement linear regression and random forest regression models.\n",
    "5. Evaluate the models and compare their respective scores like R2, RMSE, etc.\n",
    "\n",
    "- Dataset link: https://www.kaggle.com/datasets/yasserh/uber-fares-dataset\n",
    "- Dataset available in [Datasets](https://git.kska.io/sppu-be-comp-content/MachineLearning/src/branch/main/Datasets/) directory.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "10f4a878-d398-4db5-bdf0-2132ad22c696",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# Uber Fare Prediction\n",
    "# ---------------------------------------------------------------\n",
    "# Steps:\n",
    "# 1. Data Loading and Pre-processing\n",
    "# 2. Outlier Detection\n",
    "# 3. Correlation Analysis\n",
    "# 4. Model Implementation (Linear Regression & Random Forest)\n",
    "# 5. Model Evaluation and Comparison\n",
    "# ---------------------------------------------------------------"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "f5981ab8-b381-40fa-b8ba-ffced9b4c31b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import necessary libraries\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.linear_model import LinearRegression\n",
    "from sklearn.ensemble import RandomForestRegressor\n",
    "from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error\n",
    "from math import radians, cos, sin, asin, sqrt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "c8e1b095-8f66-4035-8bb7-431767dcf755",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Initial Data Shape: (200000, 9)\n",
      "   Unnamed: 0                            key  fare_amount  \\\n",
      "0    24238194    2015-05-07 19:52:06.0000003          7.5   \n",
      "1    27835199    2009-07-17 20:04:56.0000002          7.7   \n",
      "2    44984355   2009-08-24 21:45:00.00000061         12.9   \n",
      "3    25894730    2009-06-26 08:22:21.0000001          5.3   \n",
      "4    17610152  2014-08-28 17:47:00.000000188         16.0   \n",
      "\n",
      "           pickup_datetime  pickup_longitude  pickup_latitude  \\\n",
      "0  2015-05-07 19:52:06 UTC        -73.999817        40.738354   \n",
      "1  2009-07-17 20:04:56 UTC        -73.994355        40.728225   \n",
      "2  2009-08-24 21:45:00 UTC        -74.005043        40.740770   \n",
      "3  2009-06-26 08:22:21 UTC        -73.976124        40.790844   \n",
      "4  2014-08-28 17:47:00 UTC        -73.925023        40.744085   \n",
      "\n",
      "   dropoff_longitude  dropoff_latitude  passenger_count  \n",
      "0         -73.999512         40.723217                1  \n",
      "1         -73.994710         40.750325                1  \n",
      "2         -73.962565         40.772647                1  \n",
      "3         -73.965316         40.803349                3  \n",
      "4         -73.973082         40.761247                5  \n",
      "After dropping missing values: (199999, 9)\n",
      "\n",
      "Columns after feature extraction:\n",
      " Index(['Unnamed: 0', 'fare_amount', 'pickup_longitude', 'pickup_latitude',\n",
      "       'dropoff_longitude', 'dropoff_latitude', 'passenger_count', 'hour',\n",
      "       'day', 'month', 'year', 'day_of_week'],\n",
      "      dtype='object')\n"
     ]
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 1. DATA LOADING & PREPROCESSING\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "# Load the dataset\n",
    "df = pd.read_csv(\"uber.csv\")   # change to your local path if needed\n",
    "print(\"Initial Data Shape:\", df.shape)\n",
    "print(df.head())\n",
    "\n",
    "# Drop rows with missing values\n",
    "df.dropna(inplace=True)\n",
    "print(\"After dropping missing values:\", df.shape)\n",
    "\n",
    "# Rename columns for easier reference\n",
    "df.rename(columns={'pickup_datetime': 'pickup_datetime'}, inplace=True)\n",
    "\n",
    "# Convert pickup_datetime to datetime object\n",
    "df['pickup_datetime'] = pd.to_datetime(df['pickup_datetime'], errors='coerce')\n",
    "\n",
    "# Extract useful datetime features\n",
    "df['hour'] = df['pickup_datetime'].dt.hour\n",
    "df['day'] = df['pickup_datetime'].dt.day\n",
    "df['month'] = df['pickup_datetime'].dt.month\n",
    "df['year'] = df['pickup_datetime'].dt.year\n",
    "df['day_of_week'] = df['pickup_datetime'].dt.dayofweek\n",
    "\n",
    "# Drop datetime column (not needed as a direct feature)\n",
    "df.drop(['pickup_datetime', 'key'], axis=1, inplace=True, errors='ignore')\n",
    "\n",
    "print(\"\\nColumns after feature extraction:\\n\", df.columns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "4cf6a6e6-0a4f-42f5-9776-985c8ab709ea",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Data shape after removing outliers: (199875, 12)\n"
     ]
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 2. OUTLIER DETECTION & REMOVAL\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "# Remove entries with unrealistic fares\n",
    "df = df[(df['fare_amount'] > 0) & (df['fare_amount'] < 100)]\n",
    "\n",
    "# Remove unrealistic latitude and longitude values\n",
    "df = df[(df['pickup_latitude'] <= 90) & (df['pickup_latitude'] >= -90)]\n",
    "df = df[(df['dropoff_latitude'] <= 90) & (df['dropoff_latitude'] >= -90)]\n",
    "df = df[(df['pickup_longitude'] <= 180) & (df['pickup_longitude'] >= -180)]\n",
    "df = df[(df['dropoff_longitude'] <= 180) & (df['dropoff_longitude'] >= -180)]\n",
    "\n",
    "print(\"Data shape after removing outliers:\", df.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "21d7c5de-f234-481e-a093-3908e7595635",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 3. FEATURE ENGINEERING – DISTANCE CALCULATION\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "# Define Haversine function to calculate distance between pickup and drop-off\n",
    "def haversine(lat1, lon1, lat2, lon2):\n",
    "    # convert decimal degrees to radians\n",
    "    lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])\n",
    "    # haversine formula\n",
    "    dlon = lon2 - lon1\n",
    "    dlat = lat2 - lat1\n",
    "    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2\n",
    "    c = 2 * asin(sqrt(a))\n",
    "    km = 6371 * c\n",
    "    return km\n",
    "\n",
    "# Apply the Haversine formula\n",
    "df['distance_km'] = df.apply(lambda x: haversine(x['pickup_latitude'], x['pickup_longitude'],\n",
    "                                                 x['dropoff_latitude'], x['dropoff_longitude']), axis=1)\n",
    "\n",
    "# Remove zero-distance trips\n",
    "df = df[df['distance_km'] > 0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "882683de-7a3b-4038-818e-a3a4ef3310f8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 196588 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 4. CORRELATION ANALYSIS\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "sns.heatmap(df.corr(), annot=True, cmap='coolwarm')\n",
    "plt.title(\"Feature Correlation Heatmap\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "2a90ca74-ca31-46c6-9455-41ba3e423e2c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 5. MODEL TRAINING\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "# Define features and target\n",
    "X = df[['distance_km', 'hour', 'day', 'month', 'year', 'day_of_week']]\n",
    "y = df['fare_amount']\n",
    "\n",
    "# Split data into train and test sets\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n",
    "\n",
    "# -------------------- Linear Regression --------------------\n",
    "lr_model = LinearRegression()\n",
    "lr_model.fit(X_train, y_train)\n",
    "y_pred_lr = lr_model.predict(X_test)\n",
    "\n",
    "# -------------------- Random Forest Regression --------------------\n",
    "rf_model = RandomForestRegressor(n_estimators=100, random_state=42)\n",
    "rf_model.fit(X_train, y_train)\n",
    "y_pred_rf = rf_model.predict(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "b06b0e54-47a0-44b9-b5f3-49467175cdf4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Model: Linear Regression\n",
      "R² Score: 0.0172\n",
      "RMSE: 9.4318\n",
      "MAE: 5.9225\n",
      "\n",
      "Model: Random Forest Regressor\n",
      "R² Score: 0.8190\n",
      "RMSE: 4.0477\n",
      "MAE: 2.1524\n"
     ]
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 6. MODEL EVALUATION\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "def evaluate_model(y_true, y_pred, model_name):\n",
    "    r2 = r2_score(y_true, y_pred)\n",
    "    rmse = np.sqrt(mean_squared_error(y_true, y_pred))\n",
    "    mae = mean_absolute_error(y_true, y_pred)\n",
    "    print(f\"\\nModel: {model_name}\")\n",
    "    print(f\"R² Score: {r2:.4f}\")\n",
    "    print(f\"RMSE: {rmse:.4f}\")\n",
    "    print(f\"MAE: {mae:.4f}\")\n",
    "    return r2, rmse, mae\n",
    "\n",
    "# Evaluate both models\n",
    "lr_scores = evaluate_model(y_test, y_pred_lr, \"Linear Regression\")\n",
    "rf_scores = evaluate_model(y_test, y_pred_rf, \"Random Forest Regressor\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "38e674ba-dc3e-4fca-918a-c202753b37cf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Model Comparison:\n",
      "                     Model        R2      RMSE       MAE\n",
      "0        Linear Regression  0.017172  9.431814  5.922463\n",
      "1  Random Forest Regressor  0.818988  4.047719  2.152362\n"
     ]
    }
   ],
   "source": [
    "# ---------------------------------------------------------------\n",
    "# 7. COMPARISON\n",
    "# ---------------------------------------------------------------\n",
    "\n",
    "results = pd.DataFrame({\n",
    "    'Model': ['Linear Regression', 'Random Forest Regressor'],\n",
    "    'R2': [lr_scores[0], rf_scores[0]],\n",
    "    'RMSE': [lr_scores[1], rf_scores[1]],\n",
    "    'MAE': [lr_scores[2], rf_scores[2]]\n",
    "})\n",
    "\n",
    "print(\"\\nModel Comparison:\")\n",
    "print(results)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "d72b8823-3533-47ef-a305-f37e14f6ce42",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26712 characters]",
      "text/plain": [
       "<Figure size 800x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot comparison\n",
    "plt.figure(figsize=(8,5))\n",
    "sns.barplot(x='Model', y='R2', data=results)\n",
    "plt.title(\"R² Score Comparison between Models\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "731476f9-04b8-4960-aa1f-98475ab9aeb5",
   "metadata": {},
   "source": [
    "---"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.20"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
