{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8b354d8b-a4a2-4e02-a73e-ce24eeac55bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "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": 3,
   "id": "4a3ff8e4-5389-4a25-b4db-58501f98396b",
   "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"
     ]
    }
   ],
   "source": [
    "# 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())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d63096b2-9e62-4990-815d-7ff3e0068e53",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Rename columns for easier reference\n",
    "df.rename(columns={'pickup_datetime': 'pickup_datetime'}, inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "3f183946-0d1d-4d50-93c3-717b6fc4738c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Convert pickup_datetime to datetime object\n",
    "df['pickup_datetime'] = pd.to_datetime(df['pickup_datetime'], errors='coerce')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "62ff6d20-f7b7-45df-b62b-3d6fa49f7bd5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 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"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bc22e7c2-3de0-4437-865d-621bc7694219",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\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": [
    "# 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": 8,
   "id": "76b4cc1e-dea3-49c2-bb24-822beb32c403",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Remove entries with unrealistic fares\n",
    "df = df[(df['fare_amount'] > 0) & (df['fare_amount'] < 100)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "38917ebe-66f3-4e01-b4aa-b889002f50e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 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)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "a4ce6c2c-9c01-479a-a141-ecd51ea5e2ed",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Data shape after removing outliers: (199875, 12)\n"
     ]
    }
   ],
   "source": [
    "print(\"Data shape after removing outliers:\", df.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2787dd74-c8eb-4d0d-bfa8-c0f5c7164224",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 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"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "9aa3dbc8-0169-49b5-b2b8-1a91365d153d",
   "metadata": {},
   "outputs": [],
   "source": [
    "#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)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "37beba86-0558-4b0c-9c68-c9f300f9f16a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Remove zero-distance trips\n",
    "df = df[df['distance_km'] > 0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4be478a5-cfe2-4627-b1d4-f9c6cc8aa8f1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 194192 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "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": 16,
   "id": "d5aa306e-e12e-4463-b625-317422e3e834",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define features and target\n",
    "X = df[['distance_km', 'hour', 'day', 'month', 'year', 'day_of_week']]\n",
    "y = df['fare_amount']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "a893974d-4c54-4771-b76a-99a688d29df2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 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)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "59775dd4-dc91-4442-9d0f-12c8d0753034",
   "metadata": {},
   "outputs": [],
   "source": [
    "# -------------------- Linear Regression --------------------\n",
    "lr_model = LinearRegression()\n",
    "lr_model.fit(X_train, y_train)\n",
    "y_pred_lr = lr_model.predict(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "d1a967bc-4597-4e57-a73b-a52aa9f2727b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# -------------------- 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": 20,
   "id": "13e2ec7c-aa6b-4343-98d5-58d0bb2c5ea2",
   "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": [
    "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": 21,
   "id": "0be29f33-dbf6-4ee7-8c26-995bd1402bbc",
   "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.818989  4.047705  2.152357\n"
     ]
    }
   ],
   "source": [
    "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": 22,
   "id": "c1ec0d4d-ff96-4b43-92c9-e5b081f468cb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26460 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": "code",
   "execution_count": null,
   "id": "9d5fa235-a121-4315-8dd2-b93b449c45a9",
   "metadata": {},
   "outputs": [],
   "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.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
