{
"cells": [
{
"cell_type": "markdown",
"id": "6811879a",
"metadata": {},
"source": [
"## Step 1: Import Libraries"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "7b3d945e",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import json\n",
"import joblib\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"\n",
"from sklearn.model_selection import train_test_split\n",
"from sklearn.preprocessing import LabelEncoder\n",
"from sklearn.linear_model import LogisticRegression\n",
"from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, f1_score, log_loss\n",
"\n",
"sns.set_style('whitegrid')\n",
"pd.set_option('display.max_columns', None)"
]
},
{
"cell_type": "markdown",
"id": "5bdfd552",
"metadata": {},
"source": [
"## Step 2: Load Dataset"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "c92ab153",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset shape: (11789, 25)\n"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" age | \n",
" monthly_income | \n",
" daily_internet_hours | \n",
" smartphone_usage_years | \n",
" social_media_hours | \n",
" online_payment_trust_score | \n",
" tech_savvy_score | \n",
" monthly_online_orders | \n",
" monthly_store_visits | \n",
" avg_online_spend | \n",
" avg_store_spend | \n",
" discount_sensitivity | \n",
" return_frequency | \n",
" avg_delivery_days | \n",
" delivery_fee_sensitivity | \n",
" free_return_importance | \n",
" product_availability_online | \n",
" impulse_buying_score | \n",
" need_touch_feel_score | \n",
" brand_loyalty_score | \n",
" environmental_awareness | \n",
" time_pressure_level | \n",
" gender | \n",
" city_tier | \n",
" shopping_preference | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 56 | \n",
" 221111 | \n",
" 6.5 | \n",
" 12 | \n",
" 0.7 | \n",
" 1 | \n",
" 6 | \n",
" 16 | \n",
" 16 | \n",
" 28551 | \n",
" 144092 | \n",
" 2 | \n",
" 3 | \n",
" 2 | \n",
" 6 | \n",
" 7 | \n",
" 7 | \n",
" 1 | \n",
" 3 | \n",
" 6 | \n",
" 5 | \n",
" 2 | \n",
" Other | \n",
" Tier 3 | \n",
" Store | \n",
"
\n",
" \n",
" | 1 | \n",
" 69 | \n",
" 96029 | \n",
" 8.2 | \n",
" 13 | \n",
" 2.7 | \n",
" 6 | \n",
" 9 | \n",
" 14 | \n",
" 1 | \n",
" 124056 | \n",
" 28421 | \n",
" 4 | \n",
" 7 | \n",
" 4 | \n",
" 1 | \n",
" 3 | \n",
" 4 | \n",
" 9 | \n",
" 6 | \n",
" 8 | \n",
" 1 | \n",
" 7 | \n",
" Male | \n",
" Tier 3 | \n",
" Hybrid | \n",
"
\n",
" \n",
" | 2 | \n",
" 46 | \n",
" 19055 | \n",
" 6.4 | \n",
" 4 | \n",
" 2.1 | \n",
" 10 | \n",
" 8 | \n",
" 2 | \n",
" 0 | \n",
" 81939 | \n",
" 128229 | \n",
" 9 | \n",
" 4 | \n",
" 5 | \n",
" 3 | \n",
" 4 | \n",
" 10 | \n",
" 1 | \n",
" 1 | \n",
" 3 | \n",
" 3 | \n",
" 3 | \n",
" Female | \n",
" Tier 3 | \n",
" Store | \n",
"
\n",
" \n",
" | 3 | \n",
" 32 | \n",
" 53170 | \n",
" 6.4 | \n",
" 11 | \n",
" 0.7 | \n",
" 2 | \n",
" 10 | \n",
" 20 | \n",
" 3 | \n",
" 35901 | \n",
" 134650 | \n",
" 7 | \n",
" 0 | \n",
" 3 | \n",
" 3 | \n",
" 10 | \n",
" 2 | \n",
" 4 | \n",
" 8 | \n",
" 2 | \n",
" 6 | \n",
" 6 | \n",
" Female | \n",
" Tier 1 | \n",
" Store | \n",
"
\n",
" \n",
" | 4 | \n",
" 60 | \n",
" 244016 | \n",
" 6.0 | \n",
" 5 | \n",
" 0.7 | \n",
" 2 | \n",
" 5 | \n",
" 18 | \n",
" 16 | \n",
" 131971 | \n",
" 34122 | \n",
" 5 | \n",
" 9 | \n",
" 2 | \n",
" 4 | \n",
" 2 | \n",
" 5 | \n",
" 8 | \n",
" 9 | \n",
" 7 | \n",
" 1 | \n",
" 6 | \n",
" Male | \n",
" Tier 3 | \n",
" Store | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" age monthly_income daily_internet_hours smartphone_usage_years \\\n",
"0 56 221111 6.5 12 \n",
"1 69 96029 8.2 13 \n",
"2 46 19055 6.4 4 \n",
"3 32 53170 6.4 11 \n",
"4 60 244016 6.0 5 \n",
"\n",
" social_media_hours online_payment_trust_score tech_savvy_score \\\n",
"0 0.7 1 6 \n",
"1 2.7 6 9 \n",
"2 2.1 10 8 \n",
"3 0.7 2 10 \n",
"4 0.7 2 5 \n",
"\n",
" monthly_online_orders monthly_store_visits avg_online_spend \\\n",
"0 16 16 28551 \n",
"1 14 1 124056 \n",
"2 2 0 81939 \n",
"3 20 3 35901 \n",
"4 18 16 131971 \n",
"\n",
" avg_store_spend discount_sensitivity return_frequency avg_delivery_days \\\n",
"0 144092 2 3 2 \n",
"1 28421 4 7 4 \n",
"2 128229 9 4 5 \n",
"3 134650 7 0 3 \n",
"4 34122 5 9 2 \n",
"\n",
" delivery_fee_sensitivity free_return_importance \\\n",
"0 6 7 \n",
"1 1 3 \n",
"2 3 4 \n",
"3 3 10 \n",
"4 4 2 \n",
"\n",
" product_availability_online impulse_buying_score need_touch_feel_score \\\n",
"0 7 1 3 \n",
"1 4 9 6 \n",
"2 10 1 1 \n",
"3 2 4 8 \n",
"4 5 8 9 \n",
"\n",
" brand_loyalty_score environmental_awareness time_pressure_level gender \\\n",
"0 6 5 2 Other \n",
"1 8 1 7 Male \n",
"2 3 3 3 Female \n",
"3 2 6 6 Female \n",
"4 7 1 6 Male \n",
"\n",
" city_tier shopping_preference \n",
"0 Tier 3 Store \n",
"1 Tier 3 Hybrid \n",
"2 Tier 3 Store \n",
"3 Tier 1 Store \n",
"4 Tier 3 Store "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"shopping_preference\n",
"Store 10244\n",
"Online 1176\n",
"Hybrid 369\n",
"Name: count, dtype: int64\n"
]
}
],
"source": [
"data_path = r'd:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\dataset\\Consumer_Shopping_Trends_2026 (6).csv'\n",
"\n",
"df = pd.read_csv(data_path)\n",
"\n",
"print('Dataset shape:', df.shape)\n",
"display(df.head())\n",
"\n",
"target_column = 'shopping_preference'\n",
"print(df[target_column].value_counts())"
]
},
{
"cell_type": "markdown",
"id": "5007a197",
"metadata": {},
"source": [
"## Step 3: Prepare Data"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "ce15f887",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"X_train shape: (9431, 28)\n",
"X_test shape: (2358, 28)\n",
"Classes: ['Hybrid', 'Online', 'Store']\n"
]
}
],
"source": [
"X = df.drop(columns=[target_column])\n",
"y_text = df[target_column]\n",
"\n",
"label_encoder = LabelEncoder()\n",
"y = label_encoder.fit_transform(y_text)\n",
"\n",
"X = pd.get_dummies(X, drop_first=False)\n",
"\n",
"X_train, X_test, y_train, y_test = train_test_split(\n",
" X,\n",
" y,\n",
" test_size=0.2,\n",
" random_state=3,\n",
" stratify=y\n",
")\n",
"\n",
"print('X_train shape:', X_train.shape)\n",
"print('X_test shape:', X_test.shape)\n",
"print('Classes:', list(label_encoder.classes_))"
]
},
{
"cell_type": "markdown",
"id": "9254a2e1",
"metadata": {},
"source": [
"## Step 4: Train Logistic Regression Model"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "f01a450c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model training completed\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\.venv\\Lib\\site-packages\\sklearn\\linear_model\\_logistic.py:406: ConvergenceWarning: lbfgs failed to converge after 5000 iteration(s) (status=1):\n",
"STOP: TOTAL NO. OF ITERATIONS REACHED LIMIT\n",
"\n",
"Increase the number of iterations to improve the convergence (max_iter=5000).\n",
"You might also want to scale the data as shown in:\n",
" https://scikit-learn.org/stable/modules/preprocessing.html\n",
"Please also refer to the documentation for alternative solver options:\n",
" https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
" n_iter_i = _check_optimize_result(\n"
]
}
],
"source": [
"model = LogisticRegression(max_iter=5000)\n",
"model.fit(X_train, y_train)\n",
"\n",
"y_pred = model.predict(X_test)\n",
"y_prob = model.predict_proba(X_test)\n",
"\n",
"print('Model training completed')"
]
},
{
"cell_type": "markdown",
"id": "02bf8a01",
"metadata": {},
"source": [
"## Step 5: Check Model Performance"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "d3fec84a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Accuracy: 0.9881\n",
"Weighted F1 Score: 0.9883\n",
"Log Loss: 0.0237\n",
"\n",
"Classification Report:\n",
"\n",
" precision recall f1-score support\n",
"\n",
" Hybrid 0.79 0.85 0.82 74\n",
" Online 0.97 0.96 0.97 235\n",
" Store 1.00 1.00 1.00 2049\n",
"\n",
" accuracy 0.99 2358\n",
" macro avg 0.92 0.94 0.93 2358\n",
"weighted avg 0.99 0.99 0.99 2358\n",
"\n"
]
}
],
"source": [
"accuracy = accuracy_score(y_test, y_pred)\n",
"f1 = f1_score(y_test, y_pred, average='weighted')\n",
"loss = log_loss(y_test, y_prob)\n",
"\n",
"print('Accuracy:', round(accuracy, 4))\n",
"print('Weighted F1 Score:', round(f1, 4))\n",
"print('Log Loss:', round(loss, 4))\n",
"\n",
"pred_labels = label_encoder.inverse_transform(y_pred)\n",
"true_labels = label_encoder.inverse_transform(y_test)\n",
"\n",
"print('\\nClassification Report:\\n')\n",
"print(classification_report(true_labels, pred_labels))"
]
},
{
"cell_type": "markdown",
"id": "6030171e",
"metadata": {},
"source": [
"## Step 6: Plot Confusion Matrix"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "017aecb3",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"cm = confusion_matrix(y_test, y_pred)\n",
"\n",
"plt.figure(figsize=(6, 5))\n",
"sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n",
" xticklabels=label_encoder.classes_,\n",
" yticklabels=label_encoder.classes_)\n",
"plt.xlabel('Predicted')\n",
"plt.ylabel('Actual')\n",
"plt.title('Confusion Matrix')\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "dacb3094",
"metadata": {},
"source": [
"## Step 7: Save Final Predictions"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "51e06c3f",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Actual | \n",
" Predicted | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 1 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 2 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 3 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 4 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 5 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 6 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 7 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 8 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 9 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 10 | \n",
" Online | \n",
" Online | \n",
"
\n",
" \n",
" | 11 | \n",
" Online | \n",
" Online | \n",
"
\n",
" \n",
" | 12 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 13 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
" | 14 | \n",
" Store | \n",
" Store | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Actual Predicted\n",
"0 Store Store\n",
"1 Store Store\n",
"2 Store Store\n",
"3 Store Store\n",
"4 Store Store\n",
"5 Store Store\n",
"6 Store Store\n",
"7 Store Store\n",
"8 Store Store\n",
"9 Store Store\n",
"10 Online Online\n",
"11 Online Online\n",
"12 Store Store\n",
"13 Store Store\n",
"14 Store Store"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Saved file: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\Consumer_Shopping_Trends\\metrics\\prediction.csv\n"
]
}
],
"source": [
"results = pd.DataFrame({\n",
" 'Actual': true_labels,\n",
" 'Predicted': pred_labels\n",
"})\n",
"\n",
"display(results.head(15))\n",
"\n",
"base_output = r'd:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\Consumer_Shopping_Trends'\n",
"model_dir = os.path.join(base_output, 'model')\n",
"metrics_dir = os.path.join(base_output, 'metrics')\n",
"\n",
"os.makedirs(model_dir, exist_ok=True)\n",
"os.makedirs(metrics_dir, exist_ok=True)\n",
"\n",
"save_path = os.path.join(metrics_dir, 'prediction.csv')\n",
"results.to_csv(save_path, index=False)\n",
"print('Saved file:', save_path)"
]
},
{
"cell_type": "markdown",
"id": "f5938c3f",
"metadata": {},
"source": [
"## Step 8: Final Summary"
]
},
{
"cell_type": "code",
"execution_count": 37,
"id": "86f32c22",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" Metric | \n",
" Value | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" Accuracy | \n",
" 0.988126 | \n",
"
\n",
" \n",
" | 1 | \n",
" Weighted F1 | \n",
" 0.988326 | \n",
"
\n",
" \n",
" | 2 | \n",
" Log Loss | \n",
" 0.023689 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Metric Value\n",
"0 Accuracy 0.988126\n",
"1 Weighted F1 0.988326\n",
"2 Log Loss 0.023689"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Target classes: ['Hybrid', 'Online', 'Store']\n",
"Saved model: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\Consumer_Shopping_Trends\\model\\model.joblib\n",
"Saved columns: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\Consumer_Shopping_Trends\\model\\feature_columns.json\n",
"Saved labels: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\Consumer_Shopping_Trends\\model\\label_classes.json\n",
"Saved target info: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\Consumer_Shopping_Trends\\model\\target_info.json\n",
"Saved metrics: d:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\Consumer_Shopping_Trends\\metrics\\final_metircs.csv\n"
]
}
],
"source": [
"summary = pd.DataFrame([\n",
" {'Metric': 'Accuracy', 'Value': accuracy},\n",
" {'Metric': 'Weighted F1', 'Value': f1},\n",
" {'Metric': 'Log Loss', 'Value': loss}\n",
"])\n",
"\n",
"display(summary)\n",
"print('Target classes:', list(label_encoder.classes_))\n",
"\n",
"base_output = r'd:\\B.Tech\\Semester 04\\01 Machine Learning\\LabAssginment\\outputs\\Consumer_Shopping_Trends'\n",
"model_dir = os.path.join(base_output, 'model')\n",
"metrics_dir = os.path.join(base_output, 'metrics')\n",
"\n",
"os.makedirs(model_dir, exist_ok=True)\n",
"os.makedirs(metrics_dir, exist_ok=True)\n",
"\n",
"model_path = os.path.join(model_dir, 'model.joblib')\n",
"columns_path = os.path.join(model_dir, 'feature_columns.json')\n",
"labels_path = os.path.join(model_dir, 'label_classes.json')\n",
"info_path = os.path.join(model_dir, 'target_info.json')\n",
"metrics_path = os.path.join(metrics_dir, 'final_metircs.csv')\n",
"\n",
"joblib.dump(model, model_path)\n",
"with open(columns_path, 'w', encoding='utf-8') as f:\n",
" json.dump(list(X.columns), f, indent=2)\n",
"with open(labels_path, 'w', encoding='utf-8') as f:\n",
" json.dump(list(label_encoder.classes_), f, indent=2)\n",
"with open(info_path, 'w', encoding='utf-8') as f:\n",
" json.dump({'target_col': target_column, 'model_name': 'LogisticRegression'}, f, indent=2)\n",
"summary.to_csv(metrics_path, index=False)\n",
"\n",
"print('Saved model:', model_path)\n",
"print('Saved columns:', columns_path)\n",
"print('Saved labels:', labels_path)\n",
"print('Saved target info:', info_path)\n",
"print('Saved metrics:', metrics_path)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}