{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "klg2JF-oBblG" }, "source": [ "# Problem Statement" ] }, { "cell_type": "markdown", "metadata": { "id": "m0CcOjZ-BblL" }, "source": [ "## **Business Context**" ] }, { "cell_type": "markdown", "metadata": { "id": "uyT6Koe7BblM" }, "source": [ "\"Visit with Us,\" a leading travel company, is revolutionizing the tourism industry by leveraging data-driven strategies to optimize operations and customer engagement. While introducing a new package offering, such as the Wellness Tourism Package, the company faces challenges in targeting the right customers efficiently. The manual approach to identifying potential customers is inconsistent, time-consuming, and prone to errors, leading to missed opportunities and suboptimal campaign performance.\n", "\n", "To address these issues, the company aims to implement a scalable and automated system that integrates customer data, predicts potential buyers, and enhances decision-making for marketing strategies. By utilizing an MLOps pipeline, the company seeks to achieve seamless integration of data preprocessing, model development, deployment, and CI/CD practices for continuous improvement. This system will ensure efficient targeting of customers, timely updates to the predictive model, and adaptation to evolving customer behaviors, ultimately driving growth and customer satisfaction.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "zm6bNQOJBblO" }, "source": [ "## **Objective**" ] }, { "cell_type": "markdown", "metadata": { "id": "7PYtjk_YBblO" }, "source": [ "As an MLOps Engineer at \"Visit with Us,\" your responsibility is to design and deploy an MLOps pipeline on GitHub to automate the end-to-end workflow for predicting customer purchases. The primary objective is to build a model that predicts whether a customer will purchase the newly introduced Wellness Tourism Package before contacting them. The pipeline will include data cleaning, preprocessing, transformation, model building, training, evaluation, and deployment, ensuring consistent performance and scalability. By leveraging GitHub Actions for CI/CD integration, the system will enable automated updates, streamline model deployment, and improve operational efficiency. This robust predictive solution will empower policymakers to make data-driven decisions, enhance marketing strategies, and effectively target potential customers, thereby driving customer acquisition and business growth." ] }, { "cell_type": "markdown", "metadata": { "id": "z8C11AzTBblP" }, "source": [ "## **Data Description**" ] }, { "cell_type": "markdown", "metadata": { "id": "9DQx3pkaBblP" }, "source": [ "The dataset contains customer and interaction data that serve as key attributes for predicting the likelihood of purchasing the Wellness Tourism Package. The detailed attributes are:\n", "\n", "**Customer Details**\n", "- **CustomerID:** Unique identifier for each customer.\n", "- **ProdTaken:** Target variable indicating whether the customer has purchased a package (0: No, 1: Yes).\n", "- **Age:** Age of the customer.\n", "- **TypeofContact:** The method by which the customer was contacted (Company Invited or Self Inquiry).\n", "- **CityTier:** The city category based on development, population, and living standards (Tier 1 > Tier 2 > Tier 3).\n", "- **Occupation:** Customer's occupation (e.g., Salaried, Freelancer).\n", "- **Gender:** Gender of the customer (Male, Female).\n", "- **NumberOfPersonVisiting:** Total number of people accompanying the customer on the trip.\n", "- **PreferredPropertyStar:** Preferred hotel rating by the customer.\n", "- **MaritalStatus:** Marital status of the customer (Single, Married, Divorced).\n", "- **NumberOfTrips:** Average number of trips the customer takes annually.\n", "- **Passport:** Whether the customer holds a valid passport (0: No, 1: Yes).\n", "- **OwnCar:** Whether the customer owns a car (0: No, 1: Yes).\n", "- **NumberOfChildrenVisiting:** Number of children below age 5 accompanying the customer.\n", "- **Designation:** Customer's designation in their current organization.\n", "- **MonthlyIncome:** Gross monthly income of the customer.\n", "\n", "**Customer Interaction Data**\n", "- **PitchSatisfactionScore:** Score indicating the customer's satisfaction with the sales pitch.\n", "- **ProductPitched:** The type of product pitched to the customer.\n", "- **NumberOfFollowups:** Total number of follow-ups by the salesperson after the sales pitch.-\n", "- **DurationOfPitch:** Duration of the sales pitch delivered to the customer.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "0LbSu_p2jYfe" }, "source": [ "# Model Building" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "colab": { "base_uri": "https://colab.research.google.com/" }, "id": "giodc4KknHID" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/content\n" ] } ], "source": [ "# Create a master folder to keep all files created when executing the below code cells\n", "import os\n", "print(os.getcwd())\n", "os.makedirs(\"tourism_project\", exist_ok=True)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "id": "SUKPoy0EA4jj" }, "outputs": [], "source": [ "# Create a folder for storing the model building files\n", "os.makedirs(\"tourism_project/model_building\", exist_ok=True)" ] }, { "cell_type": "markdown", "metadata": { "id": "9DtS3gNDjBbR" }, "source": [ "## Data Registration" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "id": "ZagOeVxJOtJ9" }, "outputs": [], "source": [ "os.makedirs(\"tourism_project/data\", exist_ok=True)" ] }, { "cell_type": "markdown", "metadata": { "id": "WxXiD9ZXxodF" }, "source": [ "Once the **data** folder created after executing the above cell, please upload the **tourism.csv** in to the folder" ] }, { "cell_type": "markdown", "metadata": { "id": "hh2TjRG5WJ4Z" }, "source": [ "## Data Preparation" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "colab": { "base_uri": "https://colab.research.google.com/" }, "id": "EHVRGAeoOtJ-" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing tourism_project/model_building/data_register.py\n" ] } ], "source": [ "%%writefile tourism_project/model_building/data_register.py\n", "from huggingface_hub.utils import RepositoryNotFoundError, HfHubHTTPError\n", "from huggingface_hub import HfApi, create_repo\n", "import os\n", "\n", "\n", "repo_id = \"ananttripathiak/tourism-dataset\"\n", "repo_type = \"dataset\"\n", "\n", "# Initialize API client\n", "api = HfApi(token=os.getenv(\"HF_TOKEN\"))\n", "\n", "# Step 1: Check if the space exists\n", "try:\n", " api.repo_info(repo_id=repo_id, repo_type=repo_type)\n", " print(f\"Space '{repo_id}' already exists. Using it.\")\n", "except RepositoryNotFoundError:\n", " print(f\"Space '{repo_id}' not found. Creating new space...\")\n", " create_repo(repo_id=repo_id, repo_type=repo_type, private=False)\n", " print(f\"Space '{repo_id}' created.\")\n", "\n", "api.upload_folder(\n", " folder_path=\"tourism_project/data\",\n", " repo_id=repo_id,\n", " repo_type=repo_type,\n", ")" ] }, { "cell_type": "markdown", "metadata": { "id": "eZZKnLkLjeM4" }, "source": [ "## Model Training and Registration with Experimentation Tracking" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "id": "LFmrcXT_OtJ-" }, "outputs": [], "source": [ "# !pip install mlflow scikit-learn huggingface_hub\n", "# import sys\n", "# !{sys.executable} -m pip install mlflow" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "colab": { "base_uri": "https://colab.research.google.com/" }, "id": "DatpH_YdOtJ-" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing tourism_project/model_building/train.py\n" ] } ], "source": [ "%%writefile tourism_project/model_building/train.py\n", "\n", "# for data manipulation\n", "import pandas as pd\n", "import numpy as np\n", "# for data preprocessing and pipeline creation\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.compose import make_column_transformer\n", "from sklearn.pipeline import make_pipeline\n", "# for model training, tuning, and evaluation\n", "import xgboost as xgb\n", "from sklearn.model_selection import GridSearchCV\n", "from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, classification_report, confusion_matrix\n", "# for model serialization\n", "import joblib\n", "# for creating a folder\n", "import os\n", "# for hugging face space authentication to upload files\n", "from huggingface_hub import login, HfApi, create_repo\n", "from huggingface_hub.utils import RepositoryNotFoundError, HfHubHTTPError\n", "import mlflow\n", "\n", "# Set up MLflow tracking\n", "mlflow.set_tracking_uri(\"http://localhost:5000\")\n", "mlflow.set_experiment(\"tourism-package-prediction\")\n", "\n", "api = HfApi()\n", "\n", "# Load the preprocessed data from Hugging Face\n", "Xtrain_path = \"hf://datasets/ananttripathiak/tourism-dataset/Xtrain.csv\"\n", "Xtest_path = \"hf://datasets/ananttripathiak/tourism-dataset/Xtest.csv\"\n", "ytrain_path = \"hf://datasets/ananttripathiak/tourism-dataset/ytrain.csv\"\n", "ytest_path = \"hf://datasets/ananttripathiak/tourism-dataset/ytest.csv\"\n", "\n", "print(\"Loading preprocessed data...\")\n", "Xtrain = pd.read_csv(Xtrain_path)\n", "Xtest = pd.read_csv(Xtest_path)\n", "ytrain = pd.read_csv(ytrain_path).values.ravel()\n", "ytest = pd.read_csv(ytest_path).values.ravel()\n", "\n", "print(f\"Training set shape: {Xtrain.shape}\")\n", "print(f\"Test set shape: {Xtest.shape}\")\n", "\n", "# Identify numeric features (all features after encoding)\n", "numeric_features = Xtrain.columns.tolist()\n", "\n", "# Preprocessor - StandardScaler for all numeric features\n", "preprocessor = make_column_transformer(\n", " (StandardScaler(), numeric_features)\n", ")\n", "\n", "# Define base XGBoost Classifier\n", "xgb_model = xgb.XGBClassifier(\n", " random_state=42,\n", " n_jobs=-1,\n", " eval_metric='logloss',\n", " use_label_encoder=False\n", ")\n", "\n", "# Hyperparameter grid for classification\n", "param_grid = {\n", " 'xgbclassifier__n_estimators': [100, 200, 300],\n", " 'xgbclassifier__max_depth': [3, 5, 7],\n", " 'xgbclassifier__learning_rate': [0.01, 0.05, 0.1],\n", " 'xgbclassifier__subsample': [0.7, 0.8, 1.0],\n", " 'xgbclassifier__colsample_bytree': [0.7, 0.8, 1.0],\n", " 'xgbclassifier__scale_pos_weight': [1, 2, 3] # Handle class imbalance\n", "}\n", "\n", "# Pipeline\n", "model_pipeline = make_pipeline(preprocessor, xgb_model)\n", "\n", "print(\"\\nStarting MLflow experiment...\")\n", "with mlflow.start_run():\n", " print(\"Performing Grid Search with Cross-Validation...\")\n", " # Grid Search\n", " grid_search = GridSearchCV(\n", " model_pipeline,\n", " param_grid,\n", " cv=3,\n", " n_jobs=-1,\n", " scoring='roc_auc',\n", " verbose=1\n", " )\n", " grid_search.fit(Xtrain, ytrain)\n", "\n", " # Log parameter sets\n", " results = grid_search.cv_results_\n", " print(f\"\\nEvaluated {len(results['params'])} parameter combinations\")\n", "\n", " for i in range(len(results['params'])):\n", " param_set = results['params'][i]\n", " mean_score = results['mean_test_score'][i]\n", "\n", " with mlflow.start_run(nested=True):\n", " mlflow.log_params(param_set)\n", " mlflow.log_metric(\"mean_roc_auc\", mean_score)\n", "\n", " # Best model\n", " print(f\"\\nBest parameters: {grid_search.best_params_}\")\n", " mlflow.log_params(grid_search.best_params_)\n", " best_model = grid_search.best_estimator_\n", "\n", " # Predictions\n", " print(\"\\nMaking predictions...\")\n", " y_pred_train = best_model.predict(Xtrain)\n", " y_pred_test = best_model.predict(Xtest)\n", "\n", " # Probability predictions for ROC-AUC\n", " y_pred_train_proba = best_model.predict_proba(Xtrain)[:, 1]\n", " y_pred_test_proba = best_model.predict_proba(Xtest)[:, 1]\n", "\n", " # Calculate metrics\n", " print(\"\\nCalculating metrics...\")\n", " train_accuracy = accuracy_score(ytrain, y_pred_train)\n", " test_accuracy = accuracy_score(ytest, y_pred_test)\n", "\n", " train_precision = precision_score(ytrain, y_pred_train, zero_division=0)\n", " test_precision = precision_score(ytest, y_pred_test, zero_division=0)\n", "\n", " train_recall = recall_score(ytrain, y_pred_train, zero_division=0)\n", " test_recall = recall_score(ytest, y_pred_test, zero_division=0)\n", "\n", " train_f1 = f1_score(ytrain, y_pred_train, zero_division=0)\n", " test_f1 = f1_score(ytest, y_pred_test, zero_division=0)\n", "\n", " train_roc_auc = roc_auc_score(ytrain, y_pred_train_proba)\n", " test_roc_auc = roc_auc_score(ytest, y_pred_test_proba)\n", "\n", " # Log metrics\n", " mlflow.log_metrics({\n", " \"train_accuracy\": train_accuracy,\n", " \"test_accuracy\": test_accuracy,\n", " \"train_precision\": train_precision,\n", " \"test_precision\": test_precision,\n", " \"train_recall\": train_recall,\n", " \"test_recall\": test_recall,\n", " \"train_f1_score\": train_f1,\n", " \"test_f1_score\": test_f1,\n", " \"train_roc_auc\": train_roc_auc,\n", " \"test_roc_auc\": test_roc_auc\n", " })\n", "\n", " # Print results\n", " print(\"\\n\" + \"=\"*50)\n", " print(\"MODEL PERFORMANCE METRICS\")\n", " print(\"=\"*50)\n", " print(f\"Train Accuracy: {train_accuracy:.4f} | Test Accuracy: {test_accuracy:.4f}\")\n", " print(f\"Train Precision: {train_precision:.4f} | Test Precision: {test_precision:.4f}\")\n", " print(f\"Train Recall: {train_recall:.4f} | Test Recall: {test_recall:.4f}\")\n", " print(f\"Train F1-Score: {train_f1:.4f} | Test F1-Score: {test_f1:.4f}\")\n", " print(f\"Train ROC-AUC: {train_roc_auc:.4f} | Test ROC-AUC: {test_roc_auc:.4f}\")\n", " print(\"=\"*50)\n", "\n", " print(\"\\nTest Set Classification Report:\")\n", " print(classification_report(ytest, y_pred_test, target_names=['No Purchase', 'Purchase']))\n", "\n", " print(\"\\nTest Set Confusion Matrix:\")\n", " print(confusion_matrix(ytest, y_pred_test))\n", "\n", " # Save the model locally\n", " model_path = \"best_tourism_model_v1.joblib\"\n", " joblib.dump(best_model, model_path)\n", " print(f\"\\nModel saved locally as: {model_path}\")\n", "\n", " # Log the model artifact\n", " mlflow.log_artifact(model_path, artifact_path=\"model\")\n", " print(f\"Model logged to MLflow\")\n", "\n", " # Upload to Hugging Face\n", " repo_id = \"ananttripathiak/tourism-prediction-model\"\n", " repo_type = \"model\"\n", "\n", " # Step 1: Check if the repository exists\n", " try:\n", " api.repo_info(repo_id=repo_id, repo_type=repo_type)\n", " print(f\"\\nRepository '{repo_id}' already exists. Using it.\")\n", " except RepositoryNotFoundError:\n", " print(f\"\\nRepository '{repo_id}' not found. Creating new repository...\")\n", " create_repo(repo_id=repo_id, repo_type=repo_type, private=False)\n", " print(f\"Repository '{repo_id}' created.\")\n", "\n", " # Upload model to Hugging Face\n", " api.upload_file(\n", " path_or_fileobj=\"best_tourism_model_v1.joblib\",\n", " path_in_repo=\"best_tourism_model_v1.joblib\",\n", " repo_id=repo_id,\n", " repo_type=repo_type,\n", " )\n", " print(f\"Model uploaded to Hugging Face: {repo_id}\")\n", "\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"MODEL TRAINING COMPLETED SUCCESSFULLY!\")\n", "print(\"=\"*50)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "colab": { "base_uri": "https://colab.research.google.com/" }, "id": "Vtjn_63uOtJ-" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing tourism_project/model_building/prep.py\n" ] } ], "source": [ "%%writefile tourism_project/model_building/prep.py\n", "# for data manipulation\n", "import pandas as pd\n", "import numpy as np\n", "# for data preprocessing and pipeline creation\n", "from sklearn.model_selection import train_test_split\n", "# for converting text data in to numerical representation\n", "from sklearn.preprocessing import LabelEncoder\n", "# for hugging face space authentication to upload files\n", "from huggingface_hub import login, HfApi\n", "import os\n", "\n", "# Define constants for the dataset and output paths\n", "api = HfApi(token=os.getenv(\"HF_TOKEN\"))\n", "DATASET_PATH = \"hf://datasets/ananttripathiak/tourism-dataset/tourism.csv\"\n", "df = pd.read_csv(DATASET_PATH)\n", "print(\"Dataset loaded successfully.\")\n", "print(f\"Dataset shape: {df.shape}\")\n", "\n", "# Drop the unnamed index column if it exists\n", "if 'Unnamed: 0' in df.columns or df.columns[0] == '':\n", " df = df.iloc[:, 1:]\n", "\n", "# Drop CustomerID as it's a unique identifier (not useful for modeling)\n", "if 'CustomerID' in df.columns:\n", " df.drop(columns=['CustomerID'], inplace=True)\n", "\n", "# Handle missing values\n", "print(\"\\nHandling missing values...\")\n", "# For numerical columns, fill with median\n", "numerical_cols = df.select_dtypes(include=[np.number]).columns\n", "for col in numerical_cols:\n", " if df[col].isnull().sum() > 0:\n", " df[col].fillna(df[col].median(), inplace=True)\n", "\n", "# For categorical columns, fill with mode\n", "categorical_cols = df.select_dtypes(include=['object']).columns\n", "for col in categorical_cols:\n", " if df[col].isnull().sum() > 0:\n", " df[col].fillna(df[col].mode()[0], inplace=True)\n", "\n", "# Handle specific data quality issues (e.g., \"Fe Male\" should be \"Female\")\n", "if 'Gender' in df.columns:\n", " df['Gender'] = df['Gender'].str.strip().replace({'Fe Male': 'Female', 'Fe male': 'Female'})\n", "\n", "# Encode categorical columns\n", "print(\"\\nEncoding categorical variables...\")\n", "label_encoder = LabelEncoder()\n", "\n", "# List of categorical columns to encode\n", "categorical_features = ['TypeofContact', 'Occupation', 'Gender', 'ProductPitched',\n", " 'MaritalStatus', 'Designation']\n", "\n", "for col in categorical_features:\n", " if col in df.columns:\n", " df[col] = label_encoder.fit_transform(df[col].astype(str))\n", "\n", "# Define target variable\n", "target_col = 'ProdTaken'\n", "\n", "# Split into X (features) and y (target)\n", "X = df.drop(columns=[target_col])\n", "y = df[target_col]\n", "\n", "print(f\"\\nFeatures shape: {X.shape}\")\n", "print(f\"Target shape: {y.shape}\")\n", "print(f\"Target distribution:\\n{y.value_counts()}\")\n", "\n", "# Perform train-test split\n", "Xtrain, Xtest, ytrain, ytest = train_test_split(\n", " X, y, test_size=0.2, random_state=42, stratify=y\n", ")\n", "\n", "print(f\"\\nTrain set size: {Xtrain.shape[0]}\")\n", "print(f\"Test set size: {Xtest.shape[0]}\")\n", "\n", "# Save the datasets\n", "Xtrain.to_csv(\"Xtrain.csv\", index=False)\n", "Xtest.to_csv(\"Xtest.csv\", index=False)\n", "ytrain.to_csv(\"ytrain.csv\", index=False)\n", "ytest.to_csv(\"ytest.csv\", index=False)\n", "\n", "print(\"\\nDatasets saved locally.\")\n", "\n", "# Upload to Hugging Face\n", "files = [\"Xtrain.csv\", \"Xtest.csv\", \"ytrain.csv\", \"ytest.csv\"]\n", "\n", "for file_path in files:\n", " api.upload_file(\n", " path_or_fileobj=file_path,\n", " path_in_repo=file_path.split(\"/\")[-1],\n", " repo_id=\"ananttripathiak/tourism-dataset\",\n", " repo_type=\"dataset\",\n", " )\n", " print(f\"Uploaded {file_path} to Hugging Face\")\n", "\n", "print(\"\\nData preparation completed successfully!\")" ] }, { "cell_type": "markdown", "metadata": { "id": "0McYCZzkji5I" }, "source": [ "# Deployment" ] }, { "cell_type": "markdown", "metadata": { "id": "9QrY2v77vbEZ" }, "source": [ "## Dockerfile" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "id": "0-AMAI72CR-T" }, "outputs": [], "source": [ "os.makedirs(\"tourism_project/deployment\", exist_ok=True)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "colab": { "base_uri": "https://colab.research.google.com/" }, "id": "ZTicTDnPCVZr" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing tourism_project/deployment/Dockerfile\n" ] } ], "source": [ "%%writefile tourism_project/deployment/Dockerfile\n", "# Use a minimal base image with Python 3.9 installed\n", "FROM python:3.9\n", "\n", "# Set the working directory inside the container to /app\n", "WORKDIR /app\n", "\n", "# Copy all files from the current directory on the host to the container's /app directory\n", "COPY . .\n", "\n", "# Install Python dependencies listed in requirements.txt\n", "RUN pip3 install -r requirements.txt\n", "\n", "RUN useradd -m -u 1000 user\n", "USER user\n", "ENV HOME=/home/user \\\n", "\tPATH=/home/user/.local/bin:$PATH\n", "\n", "WORKDIR $HOME/app\n", "\n", "COPY --chown=user . $HOME/app\n", "\n", "# Define the command to run the Streamlit app on port \"8501\" and make it accessible externally\n", "CMD [\"streamlit\", \"run\", \"app.py\", \"--server.port=8501\", \"--server.address=0.0.0.0\", \"--server.enableXsrfProtection=false\"]" ] }, { "cell_type": "markdown", "metadata": { "id": "LCvrklrBwNvJ" }, "source": [ "## Streamlit App" ] }, { "cell_type": "markdown", "metadata": { "id": "fXWe6ObRjP6-" }, "source": [ "Please ensure that the web app script is named `app.py`." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "colab": { "base_uri": "https://colab.research.google.com/" }, "id": "WBG-jxM89jdp" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing tourism_project/deployment/app.py\n" ] } ], "source": [ "%%writefile tourism_project/deployment/app.py\n", "import streamlit as st\n", "import pandas as pd\n", "import numpy as np\n", "from huggingface_hub import hf_hub_download\n", "import joblib\n", "\n", "# Page configuration\n", "st.set_page_config(\n", " page_title=\"Tourism Package Prediction\",\n", " page_icon=\"✈️\",\n", " layout=\"wide\"\n", ")\n", "\n", "# Download and load the trained model\n", "@st.cache_resource\n", "def load_model():\n", " try:\n", " model_path = hf_hub_download(\n", " repo_id=\"ananttripathiak/tourism-prediction-model\",\n", " filename=\"best_tourism_model_v1.joblib\"\n", " )\n", " model = joblib.load(model_path)\n", " return model\n", " except Exception as e:\n", " st.error(f\"Error loading model: {e}\")\n", " return None\n", "\n", "model = load_model()\n", "\n", "# Title and Description\n", "st.title(\"✈️ Wellness Tourism Package Prediction\")\n", "st.markdown(\"\"\"\n", "\n", "\"\"\", unsafe_allow_html=True)\n", "\n", "st.markdown(\"\"\"\n", "This application predicts the likelihood of a customer purchasing the **Wellness Tourism Package**\n", "based on their profile and interaction data. Enter customer details below to get a prediction.\n", "\"\"\")\n", "\n", "# Create two columns for input\n", "col1, col2 = st.columns(2)\n", "\n", "with col1:\n", " st.subheader(\"📋 Customer Demographics\")\n", "\n", " age = st.number_input(\"Age\", min_value=18, max_value=100, value=35, step=1)\n", "\n", " type_of_contact = st.selectbox(\n", " \"Type of Contact\",\n", " options=[\"Self Enquiry\", \"Company Invited\"]\n", " )\n", "\n", " city_tier = st.selectbox(\n", " \"City Tier\",\n", " options=[1, 2, 3],\n", " help=\"Tier 1: Metro cities, Tier 2: Mid-sized cities, Tier 3: Smaller cities\"\n", " )\n", "\n", " occupation = st.selectbox(\n", " \"Occupation\",\n", " options=[\"Salaried\", \"Small Business\", \"Free Lancer\", \"Large Business\"]\n", " )\n", "\n", " gender = st.selectbox(\"Gender\", options=[\"Male\", \"Female\"])\n", "\n", " marital_status = st.selectbox(\n", " \"Marital Status\",\n", " options=[\"Single\", \"Married\", \"Divorced\", \"Unmarried\"]\n", " )\n", "\n", " designation = st.selectbox(\n", " \"Designation\",\n", " options=[\"Executive\", \"Manager\", \"Senior Manager\", \"AVP\", \"VP\"]\n", " )\n", "\n", " monthly_income = st.number_input(\n", " \"Monthly Income (₹)\",\n", " min_value=0.0,\n", " max_value=200000.0,\n", " value=25000.0,\n", " step=1000.0\n", " )\n", "\n", "with col2:\n", " st.subheader(\"🎯 Customer Interaction & Preferences\")\n", "\n", " duration_of_pitch = st.number_input(\n", " \"Duration of Pitch (minutes)\",\n", " min_value=0.0,\n", " max_value=60.0,\n", " value=15.0,\n", " step=0.5\n", " )\n", "\n", " number_of_persons_visiting = st.number_input(\n", " \"Number of Persons Visiting\",\n", " min_value=1,\n", " max_value=10,\n", " value=2,\n", " step=1\n", " )\n", "\n", " number_of_followups = st.number_input(\n", " \"Number of Follow-ups\",\n", " min_value=0.0,\n", " max_value=10.0,\n", " value=3.0,\n", " step=1.0\n", " )\n", "\n", " product_pitched = st.selectbox(\n", " \"Product Pitched\",\n", " options=[\"Basic\", \"Standard\", \"Deluxe\", \"Super Deluxe\", \"King\"]\n", " )\n", "\n", " preferred_property_star = st.selectbox(\n", " \"Preferred Property Star Rating\",\n", " options=[3.0, 4.0, 5.0]\n", " )\n", "\n", " number_of_trips = st.number_input(\n", " \"Number of Trips (per year)\",\n", " min_value=0.0,\n", " max_value=20.0,\n", " value=3.0,\n", " step=1.0\n", " )\n", "\n", " passport = st.selectbox(\"Has Passport?\", options=[\"Yes\", \"No\"])\n", "\n", " pitch_satisfaction_score = st.slider(\n", " \"Pitch Satisfaction Score\",\n", " min_value=1,\n", " max_value=5,\n", " value=3,\n", " step=1\n", " )\n", "\n", " own_car = st.selectbox(\"Owns Car?\", options=[\"Yes\", \"No\"])\n", "\n", " number_of_children_visiting = st.number_input(\n", " \"Number of Children Visiting\",\n", " min_value=0.0,\n", " max_value=5.0,\n", " value=0.0,\n", " step=1.0\n", " )\n", "\n", "# Encoding mapping (based on LabelEncoder used during training)\n", "# Note: These mappings should match the exact encoding used during training\n", "type_of_contact_map = {\"Company Invited\": 0, \"Self Enquiry\": 1}\n", "occupation_map = {\"Free Lancer\": 0, \"Large Business\": 1, \"Salaried\": 2, \"Small Business\": 3}\n", "gender_map = {\"Female\": 0, \"Male\": 1}\n", "product_pitched_map = {\"Basic\": 0, \"Deluxe\": 1, \"King\": 2, \"Standard\": 3, \"Super Deluxe\": 4}\n", "marital_status_map = {\"Divorced\": 0, \"Married\": 1, \"Single\": 2, \"Unmarried\": 3}\n", "designation_map = {\"AVP\": 0, \"Executive\": 1, \"Manager\": 2, \"Senior Manager\": 3, \"VP\": 4}\n", "\n", "# Convert Yes/No to 0/1\n", "passport_val = 1 if passport == \"Yes\" else 0\n", "own_car_val = 1 if own_car == \"Yes\" else 0\n", "\n", "# Prepare input data\n", "input_data = pd.DataFrame([{\n", " 'Age': age,\n", " 'TypeofContact': type_of_contact_map[type_of_contact],\n", " 'CityTier': city_tier,\n", " 'DurationOfPitch': duration_of_pitch,\n", " 'Occupation': occupation_map[occupation],\n", " 'Gender': gender_map[gender],\n", " 'NumberOfPersonVisiting': number_of_persons_visiting,\n", " 'NumberOfFollowups': number_of_followups,\n", " 'ProductPitched': product_pitched_map[product_pitched],\n", " 'PreferredPropertyStar': preferred_property_star,\n", " 'MaritalStatus': marital_status_map[marital_status],\n", " 'NumberOfTrips': number_of_trips,\n", " 'Passport': passport_val,\n", " 'PitchSatisfactionScore': pitch_satisfaction_score,\n", " 'OwnCar': own_car_val,\n", " 'NumberOfChildrenVisiting': number_of_children_visiting,\n", " 'Designation': designation_map[designation],\n", " 'MonthlyIncome': monthly_income\n", "}])\n", "\n", "# Predict button\n", "st.markdown(\"---\")\n", "if st.button(\"🔮 Predict Purchase Likelihood\", use_container_width=True):\n", " if model is not None:\n", " try:\n", " # Make prediction\n", " prediction = model.predict(input_data)[0]\n", " prediction_proba = model.predict_proba(input_data)[0]\n", "\n", " # Display results\n", " st.markdown(\"### 📊 Prediction Results\")\n", "\n", " if prediction == 1:\n", " st.markdown(\n", " f'
This customer is likely to purchase the Wellness Tourism Package.
'\n", " f'Confidence: {prediction_proba[1]*100:.2f}%
'\n", " f'This customer is unlikely to purchase the Wellness Tourism Package.
'\n", " f'Confidence: {prediction_proba[0]*100:.2f}%
'\n", " f'🏢 Visit with Us - Wellness Tourism Package Prediction System
\n", "Built with ❤️ using Streamlit and XGBoost
\n", "