| | import gradio as gr |
| | import pandas as pd |
| | import numpy as np |
| | from sklearn.ensemble import RandomForestClassifier |
| | from sklearn.model_selection import train_test_split |
| | from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix |
| | import pickle |
| | import os |
| |
|
| | |
| | model = None |
| | feature_columns = None |
| |
|
| | def load_and_train_model(csv_file): |
| | """Load dataset and train a Random Forest model""" |
| | global model, feature_columns |
| | |
| | try: |
| | |
| | df = pd.read_csv(csv_file.name) |
| | |
| | |
| | if 'fraud' not in df.columns: |
| | return "❌ Error: CSV must contain a 'fraud' column as the target variable." |
| | |
| | |
| | X = df.drop(['fraud', 'transaction_id'], axis=1, errors='ignore') |
| | y = df['fraud'] |
| | |
| | feature_columns = X.columns.tolist() |
| | |
| | |
| | X_train, X_test, y_train, y_test = train_test_split( |
| | X, y, test_size=0.2, random_state=42, stratify=y |
| | ) |
| | |
| | |
| | model = RandomForestClassifier(n_estimators=100, random_state=42, max_depth=10) |
| | model.fit(X_train, y_train) |
| | |
| | |
| | y_pred = model.predict(X_test) |
| | |
| | accuracy = accuracy_score(y_test, y_pred) |
| | precision = precision_score(y_test, y_pred) |
| | recall = recall_score(y_test, y_pred) |
| | f1 = f1_score(y_test, y_pred) |
| | cm = confusion_matrix(y_test, y_pred) |
| | |
| | |
| | results = f""" |
| | ✅ **Model Trained Successfully!** |
| | |
| | 📊 **Dataset Information:** |
| | - Total Samples: {len(df)} |
| | - Training Samples: {len(X_train)} |
| | - Test Samples: {len(X_test)} |
| | - Fraud Cases: {y.sum()} ({y.mean()*100:.1f}%) |
| | - Legitimate Cases: {(y==0).sum()} ({(y==0).mean()*100:.1f}%) |
| | |
| | 📈 **Model Performance:** |
| | - **Accuracy:** {accuracy*100:.2f}% |
| | - **Precision:** {precision*100:.2f}% |
| | - **Recall:** {recall*100:.2f}% |
| | - **F1-Score:** {f1*100:.2f}% |
| | |
| | 🔢 **Confusion Matrix:** |
| | ``` |
| | Predicted |
| | Fraud Legitimate |
| | Actual Fraud {cm[1][1]} {cm[1][0]} |
| | Legit {cm[0][1]} {cm[0][0]} |
| | ``` |
| | |
| | **Key Metrics Explained:** |
| | - **True Positives (TP):** {cm[1][1]} frauds correctly detected |
| | - **False Negatives (FN):** {cm[1][0]} frauds missed (⚠️ costly!) |
| | - **False Positives (FP):** {cm[0][1]} false alarms |
| | - **True Negatives (TN):** {cm[0][0]} legitimate transactions correctly identified |
| | |
| | ✅ Model is ready! You can now make predictions below. |
| | """ |
| | |
| | return results |
| | |
| | except Exception as e: |
| | return f"❌ Error: {str(e)}" |
| |
|
| |
|
| | def predict_single_transaction(amount, hour, dist_home, dist_last, ratio_median, |
| | repeat_retailer, used_chip, used_pin, online_order): |
| | """Make a prediction for a single transaction""" |
| | global model, feature_columns |
| | |
| | if model is None: |
| | return "⚠️ Please upload and train a model first!", "" |
| | |
| | try: |
| | |
| | input_data = pd.DataFrame({ |
| | 'transaction_amount': [amount], |
| | 'transaction_hour': [hour], |
| | 'distance_from_home_km': [dist_home], |
| | 'distance_from_last_transaction_km': [dist_last], |
| | 'ratio_to_median_purchase': [ratio_median], |
| | 'repeat_retailer': [repeat_retailer], |
| | 'used_chip': [used_chip], |
| | 'used_pin': [used_pin], |
| | 'online_order': [online_order] |
| | }) |
| | |
| | |
| | prediction = model.predict(input_data)[0] |
| | probability = model.predict_proba(input_data)[0] |
| | |
| | |
| | fraud_prob = probability[1] * 100 |
| | legit_prob = probability[0] * 100 |
| | |
| | if prediction == 1: |
| | result = f"🚨 **FRAUD DETECTED**" |
| | confidence = fraud_prob |
| | color = "red" |
| | else: |
| | result = f"✅ **LEGITIMATE TRANSACTION**" |
| | confidence = legit_prob |
| | color = "green" |
| | |
| | details = f""" |
| | {result} |
| | |
| | **Confidence:** {confidence:.1f}% |
| | |
| | **Probability Distribution:** |
| | - Fraud: {fraud_prob:.1f}% |
| | - Legitimate: {legit_prob:.1f}% |
| | |
| | **Risk Level:** {'🔴 HIGH' if fraud_prob > 70 else '🟡 MEDIUM' if fraud_prob > 40 else '🟢 LOW'} |
| | |
| | **Transaction Details:** |
| | - Amount: ${amount:,.2f} |
| | - Time: {hour}:00 |
| | - Distance from home: {dist_home:.1f} km |
| | - Distance from last transaction: {dist_last:.1f} km |
| | - Ratio to median: {ratio_median:.2f}x |
| | - Repeat retailer: {'Yes' if repeat_retailer else 'No'} |
| | - Used chip: {'Yes' if used_chip else 'No'} |
| | - Used PIN: {'Yes' if used_pin else 'No'} |
| | - Online order: {'Yes' if online_order else 'No'} |
| | """ |
| | |
| | return details, result |
| | |
| | except Exception as e: |
| | return f"❌ Error: {str(e)}", "" |
| |
|
| |
|
| | def predict_batch(csv_file): |
| | """Make predictions for batch of transactions""" |
| | global model, feature_columns |
| | |
| | if model is None: |
| | return None, "⚠️ Please upload and train a model first!" |
| | |
| | try: |
| | |
| | df = pd.read_csv(csv_file.name) |
| | |
| | |
| | original_df = df.copy() |
| | |
| | |
| | X = df.drop(['fraud', 'transaction_id'], axis=1, errors='ignore') |
| | |
| | |
| | predictions = model.predict(X) |
| | probabilities = model.predict_proba(X) |
| | |
| | |
| | original_df['predicted_fraud'] = predictions |
| | original_df['fraud_probability'] = probabilities[:, 1] * 100 |
| | original_df['confidence'] = np.max(probabilities, axis=1) * 100 |
| | |
| | |
| | if 'fraud' in original_df.columns: |
| | accuracy = accuracy_score(original_df['fraud'], predictions) |
| | precision = precision_score(original_df['fraud'], predictions) |
| | recall = recall_score(original_df['fraud'], predictions) |
| | f1 = f1_score(original_df['fraud'], predictions) |
| | |
| | metrics = f""" |
| | 📊 **Batch Prediction Results:** |
| | |
| | - Total Transactions: {len(df)} |
| | - Predicted Fraud: {predictions.sum()} ({predictions.mean()*100:.1f}%) |
| | - Predicted Legitimate: {(predictions==0).sum()} ({(predictions==0).mean()*100:.1f}%) |
| | |
| | 📈 **Performance Metrics:** |
| | - Accuracy: {accuracy*100:.2f}% |
| | - Precision: {precision*100:.2f}% |
| | - Recall: {recall*100:.2f}% |
| | - F1-Score: {f1*100:.2f}% |
| | |
| | ✅ Results are ready for download! |
| | """ |
| | else: |
| | metrics = f""" |
| | 📊 **Batch Prediction Results:** |
| | |
| | - Total Transactions: {len(df)} |
| | - Predicted Fraud: {predictions.sum()} ({predictions.mean()*100:.1f}%) |
| | - Predicted Legitimate: {(predictions==0).sum()} ({(predictions==0).mean()*100:.1f}%) |
| | |
| | ✅ Results are ready for download! |
| | """ |
| | |
| | |
| | output_file = "predictions_output.csv" |
| | original_df.to_csv(output_file, index=False) |
| | |
| | return output_file, metrics |
| | |
| | except Exception as e: |
| | return None, f"❌ Error: {str(e)}" |
| |
|
| |
|
| | def calculate_business_impact(total_transactions, fraud_rate_percent, precision, recall, |
| | fraud_loss_per_transaction, review_cost_per_transaction): |
| | """Calculate the financial business impact of a fraud detection model""" |
| | |
| | try: |
| | |
| | fraud_rate = fraud_rate_percent / 100 |
| | |
| | |
| | total_frauds = int(total_transactions * fraud_rate) |
| | total_legitimate = total_transactions - total_frauds |
| | |
| | |
| | |
| | |
| | true_positives = int(recall * total_frauds) |
| | false_negatives = total_frauds - true_positives |
| | |
| | |
| | |
| | false_positives = int(true_positives / precision - true_positives) if precision > 0 else 0 |
| | true_negatives = total_legitimate - false_positives |
| | |
| | |
| | |
| | fraud_losses_prevented = true_positives * fraud_loss_per_transaction |
| | |
| | |
| | fraud_losses_incurred = false_negatives * fraud_loss_per_transaction |
| | |
| | |
| | total_flagged = true_positives + false_positives |
| | total_review_costs = total_flagged * review_cost_per_transaction |
| | |
| | |
| | net_benefit = fraud_losses_prevented - fraud_losses_incurred - total_review_costs |
| | |
| | |
| | baseline_losses = total_frauds * fraud_loss_per_transaction |
| | savings_vs_baseline = baseline_losses - fraud_losses_incurred - total_review_costs |
| | |
| | |
| | fraud_detection_rate = (true_positives / total_frauds * 100) if total_frauds > 0 else 0 |
| | false_positive_rate = (false_positives / total_legitimate * 100) if total_legitimate > 0 else 0 |
| | |
| | |
| | results = f""" |
| | ## 💰 Business Impact Analysis |
| | |
| | ### 📊 Transaction Breakdown |
| | - **Total Transactions:** {total_transactions:,} per month |
| | - **Actual Frauds:** {total_frauds:,} ({fraud_rate_percent:.2f}%) |
| | - **Legitimate Transactions:** {total_legitimate:,} ({100-fraud_rate_percent:.2f}%) |
| | |
| | ### 🎯 Model Performance |
| | - **Precision:** {precision*100:.1f}% (of flagged, {precision*100:.1f}% are actually fraud) |
| | - **Recall:** {recall*100:.1f}% (catches {recall*100:.1f}% of all frauds) |
| | |
| | ### 🔍 Detection Results |
| | - **✅ True Positives (Frauds Caught):** {true_positives:,} ({fraud_detection_rate:.1f}% of frauds) |
| | - **❌ False Negatives (Frauds Missed):** {false_negatives:,} ({100-fraud_detection_rate:.1f}% of frauds) |
| | - **⚠️ False Positives (False Alarms):** {false_positives:,} ({false_positive_rate:.2f}% of legitimate) |
| | - **✅ True Negatives (Correctly Allowed):** {true_negatives:,} |
| | |
| | ### 💵 Financial Impact (Monthly) |
| | |
| | **Fraud Prevention:** |
| | - **Losses Prevented:** ${fraud_losses_prevented:,.2f} |
| | - ({true_positives:,} frauds caught × ${fraud_loss_per_transaction:,.2f}) |
| | |
| | **Losses Incurred:** |
| | - **Missed Fraud Losses:** ${fraud_losses_incurred:,.2f} |
| | - ({false_negatives:,} frauds missed × ${fraud_loss_per_transaction:,.2f}) |
| | |
| | **Operational Costs:** |
| | - **Manual Review Costs:** ${total_review_costs:,.2f} |
| | - ({total_flagged:,} flagged transactions × ${review_cost_per_transaction:,.2f}) |
| | |
| | ### 📈 **Net Benefit: ${net_benefit:,.2f} per month** |
| | |
| | ### 🎯 **Primary Benefit:** |
| | **The model saves ${savings_vs_baseline:,.2f} per month compared to having no fraud detection system.** |
| | |
| | **Annual Impact:** ${net_benefit * 12:,.2f} |
| | |
| | ### 📊 Key Insights: |
| | 1. **Fraud Detection Rate:** {fraud_detection_rate:.1f}% of frauds are caught |
| | 2. **Cost Efficiency:** Every ${total_review_costs/fraud_losses_prevented:.2f} spent on reviews prevents ${fraud_loss_per_transaction:.2f} in fraud |
| | 3. **ROI:** {((net_benefit / total_review_costs) * 100) if total_review_costs > 0 else 0:.1f}% return on review investment |
| | 4. **Remaining Risk:** {false_negatives:,} frauds still slip through (${fraud_losses_incurred:,.2f} in losses) |
| | |
| | ### ⚠️ Recommendations: |
| | - **Current Recall ({recall*100:.1f}%):** Missing {false_negatives:,} frauds costs ${fraud_losses_incurred:,.2f}/month |
| | - Consider improving recall to reduce missed frauds |
| | - Balance precision to control review costs |
| | """ |
| | |
| | return results |
| | |
| | except Exception as e: |
| | return f"❌ Error calculating business impact: {str(e)}" |
| |
|
| |
|
| | def analyze_model_drift(initial_precision, current_precision, months_deployed, |
| | initial_recall, current_recall): |
| | """Analyze model drift and provide recommendations""" |
| | |
| | try: |
| | precision_drop = initial_precision - current_precision |
| | precision_drop_pct = (precision_drop / initial_precision * 100) if initial_precision > 0 else 0 |
| | |
| | recall_change = current_recall - initial_recall |
| | recall_change_pct = (recall_change / initial_recall * 100) if initial_recall > 0 else 0 |
| | |
| | |
| | if precision_drop_pct > 20: |
| | severity = "🔴 CRITICAL" |
| | urgency = "Immediate action required" |
| | elif precision_drop_pct > 10: |
| | severity = "🟠 HIGH" |
| | urgency = "Action needed within 1-2 weeks" |
| | else: |
| | severity = "🟡 MODERATE" |
| | urgency = "Monitor closely, plan retraining" |
| | |
| | |
| | causes = [] |
| | if precision_drop_pct > 15: |
| | causes.append({ |
| | "rank": 1, |
| | "cause": "**Data Drift / Distribution Shift**", |
| | "description": "The statistical distribution of incoming transactions has changed. Legitimate customer behavior patterns have shifted (e.g., new spending habits, new products, seasonal changes, post-pandemic behavior changes).", |
| | "probability": "Very High (80-90%)" |
| | }) |
| | else: |
| | causes.append({ |
| | "rank": 1, |
| | "cause": "**Data Drift / Distribution Shift**", |
| | "description": "Gradual changes in transaction patterns over time.", |
| | "probability": "High (70-80%)" |
| | }) |
| | |
| | causes.append({ |
| | "rank": 2, |
| | "cause": "**Concept Drift**", |
| | "description": "The relationship between features and fraud has changed. Fraudsters have adapted their tactics to evade detection, or new fraud patterns have emerged that weren't in training data.", |
| | "probability": "Medium-High (50-60%)" |
| | }) |
| | |
| | causes.append({ |
| | "rank": 3, |
| | "cause": "**Feature Drift**", |
| | "description": "Individual features have changed meaning or distribution. Examples: new payment methods, changes in merchant categories, updated transaction processing systems.", |
| | "probability": "Medium (30-40%)" |
| | }) |
| | |
| | causes.append({ |
| | "rank": 4, |
| | "cause": "**Label Quality Issues**", |
| | "description": "Ground truth labels may have become less accurate, or fraud definition has changed. This is less common but can cause apparent precision drops.", |
| | "probability": "Low (10-20%)" |
| | }) |
| | |
| | |
| | actions = [ |
| | { |
| | "priority": "🔴 IMMEDIATE", |
| | "action": "**Data Distribution Analysis**", |
| | "steps": [ |
| | "Compare feature distributions of recent data vs training data", |
| | "Use statistical tests (KS test, PSI - Population Stability Index)", |
| | "Identify which features have drifted most significantly", |
| | "Check for missing values, outliers, or data quality issues" |
| | ] |
| | }, |
| | { |
| | "priority": "🔴 IMMEDIATE", |
| | "action": "**Model Retraining**", |
| | "steps": [ |
| | "Collect recent labeled data (last 1-3 months)", |
| | "Retrain model with updated dataset", |
| | "Use time-based train/test splits (not random)", |
| | "Consider ensemble with older model for stability", |
| | "Validate on holdout set before deployment" |
| | ] |
| | }, |
| | { |
| | "priority": "🟠 HIGH", |
| | "action": "**Implement Monitoring**", |
| | "steps": [ |
| | "Set up automated drift detection (PSI, feature drift alerts)", |
| | "Track precision/recall on rolling windows (daily/weekly)", |
| | "Monitor false positive rate trends", |
| | "Alert when metrics drop below thresholds", |
| | "Dashboard for real-time model health" |
| | ] |
| | }, |
| | { |
| | "priority": "🟠 HIGH", |
| | "action": "**Threshold Adjustment**", |
| | "steps": [ |
| | "Temporarily adjust classification threshold to maintain precision", |
| | "Use probability scores instead of binary predictions", |
| | "Implement adaptive thresholds based on recent performance", |
| | "Balance precision vs recall based on business needs" |
| | ] |
| | }, |
| | { |
| | "priority": "🟡 MEDIUM", |
| | "action": "**Feature Engineering Updates**", |
| | "steps": [ |
| | "Review and update feature engineering logic", |
| | "Add new features that capture current fraud patterns", |
| | "Remove obsolete features", |
| | "Consider interaction features or time-based features" |
| | ] |
| | }, |
| | { |
| | "priority": "🟡 MEDIUM", |
| | "action": "**Continuous Learning Pipeline**", |
| | "steps": [ |
| | "Implement periodic retraining schedule (monthly/quarterly)", |
| | "Use online learning or incremental updates if applicable", |
| | "A/B test new model versions before full deployment", |
| | "Maintain model versioning and rollback capability" |
| | ] |
| | } |
| | ] |
| | |
| | |
| | |
| | |
| | impact_note = "⚠️ Lower precision means more false positives, increasing review costs and customer friction." |
| | |
| | |
| | results = f""" |
| | ## 🔍 Model Drift Analysis |
| | |
| | ### 📉 Performance Degradation |
| | - **Initial Precision:** {initial_precision*100:.1f}% |
| | - **Current Precision:** {current_precision*100:.1f}% |
| | - **Precision Drop:** {precision_drop*100:.1f} percentage points ({precision_drop_pct:.1f}% relative decrease) |
| | - **Deployment Duration:** {months_deployed} months |
| | |
| | - **Initial Recall:** {initial_recall*100:.1f}% |
| | - **Current Recall:** {current_recall*100:.1f}% |
| | - **Recall Change:** {recall_change*100:+.1f} percentage points ({recall_change_pct:+.1f}% relative change) |
| | |
| | ### {severity} - {urgency} |
| | |
| | --- |
| | |
| | ## 🎯 Most Likely Cause |
| | |
| | ### {causes[0]['rank']}. {causes[0]['cause']} |
| | **Probability:** {causes[0]['probability']} |
| | |
| | **Explanation:** |
| | {causes[0]['description']} |
| | |
| | **Why This Matters:** |
| | - Lower precision = More false positives |
| | - More legitimate transactions flagged for review |
| | - Increased operational costs and customer friction |
| | - Model is becoming less reliable over time |
| | |
| | --- |
| | |
| | ## 🔧 Appropriate Actions (Priority Order) |
| | |
| | """ |
| | |
| | for action in actions: |
| | results += f""" |
| | ### {action['priority']} {action['action']} |
| | """ |
| | for i, step in enumerate(action['steps'], 1): |
| | results += f"{i}. {step}\n" |
| | results += "\n" |
| | |
| | results += f""" |
| | --- |
| | |
| | ## 📊 Additional Considerations |
| | |
| | ### Why Precision Drops Are Critical: |
| | 1. **Financial Impact:** More false positives = higher review costs |
| | 2. **Customer Experience:** Legitimate customers face more friction |
| | 3. **Operational Burden:** Review teams overwhelmed with false alarms |
| | 4. **Trust Erosion:** Model loses credibility if too many false alarms |
| | |
| | ### Prevention Strategy: |
| | - **Proactive Monitoring:** Don't wait for metrics to drop |
| | - **Regular Retraining:** Schedule periodic model updates (every 1-3 months) |
| | - **Data Quality:** Ensure incoming data matches training data characteristics |
| | - **Feedback Loops:** Incorporate labeled outcomes back into training data |
| | |
| | ### Expected Timeline: |
| | - **Immediate (Week 1):** Data analysis, threshold adjustment |
| | - **Short-term (Weeks 2-4):** Model retraining, validation |
| | - **Long-term (Ongoing):** Continuous monitoring, scheduled retraining |
| | |
| | --- |
| | |
| | ## 💡 Key Takeaway |
| | |
| | **The most likely cause is DATA DRIFT** - your model was trained on data from 3+ months ago, and transaction patterns have changed. The model needs to be retrained on recent data to adapt to current patterns. |
| | |
| | **Action:** Implement a retraining pipeline with recent labeled data and set up continuous monitoring to catch drift early. |
| | """ |
| | |
| | return results |
| | |
| | except Exception as e: |
| | return f"❌ Error analyzing model drift: {str(e)}" |
| |
|
| |
|
| | |
| | with gr.Blocks(title="Fraud Detection System") as demo: |
| | |
| | gr.Markdown(""" |
| | # 💳 Credit Card Fraud Detection System |
| | ### AI Infinity Programme | TalentSprint |
| | |
| | This interactive demo allows you to train a fraud detection model and make predictions on credit card transactions. |
| | |
| | **How to use:** |
| | 1. Upload your training dataset (CSV file) |
| | 2. Train the model |
| | 3. Make single predictions or batch predictions |
| | """) |
| | |
| | with gr.Tab("📤 Upload & Train Model"): |
| | gr.Markdown("### Step 1: Upload Training Dataset") |
| | gr.Markdown("Upload a CSV file containing transaction data with a 'fraud' column (0 = legitimate, 1 = fraud)") |
| | |
| | with gr.Row(): |
| | with gr.Column(): |
| | train_file = gr.File(label="Upload Training CSV", file_types=[".csv"]) |
| | train_button = gr.Button("🚀 Train Model", variant="primary", size="lg") |
| | |
| | with gr.Column(): |
| | train_output = gr.Markdown(label="Training Results") |
| | |
| | train_button.click( |
| | fn=load_and_train_model, |
| | inputs=[train_file], |
| | outputs=[train_output] |
| | ) |
| | |
| | gr.Markdown(""" |
| | --- |
| | **Expected CSV format:** |
| | - `transaction_amount`, `transaction_hour`, `distance_from_home_km`, `distance_from_last_transaction_km`, |
| | - `ratio_to_median_purchase`, `repeat_retailer`, `used_chip`, `used_pin`, `online_order`, `fraud` |
| | """) |
| | |
| | with gr.Tab("🔍 Single Prediction"): |
| | gr.Markdown("### Test Individual Transactions") |
| | gr.Markdown("Enter transaction details to check if it's fraudulent") |
| | |
| | with gr.Row(): |
| | with gr.Column(): |
| | amount = gr.Number(label="Transaction Amount ($)", value=100) |
| | hour = gr.Slider(0, 23, step=1, label="Transaction Hour (0-23)", value=14) |
| | dist_home = gr.Number(label="Distance from Home (km)", value=10) |
| | dist_last = gr.Number(label="Distance from Last Transaction (km)", value=5) |
| | ratio_median = gr.Number(label="Ratio to Median Purchase", value=1.0) |
| | |
| | with gr.Column(): |
| | repeat_retailer = gr.Checkbox(label="Repeat Retailer", value=True) |
| | used_chip = gr.Checkbox(label="Used Chip", value=True) |
| | used_pin = gr.Checkbox(label="Used PIN", value=True) |
| | online_order = gr.Checkbox(label="Online Order", value=False) |
| | |
| | predict_button = gr.Button("🔮 Predict", variant="primary", size="lg") |
| | |
| | with gr.Row(): |
| | prediction_output = gr.Markdown(label="Prediction Result") |
| | prediction_label = gr.Markdown(label="Quick Result") |
| | |
| | predict_button.click( |
| | fn=predict_single_transaction, |
| | inputs=[amount, hour, dist_home, dist_last, ratio_median, |
| | repeat_retailer, used_chip, used_pin, online_order], |
| | outputs=[prediction_output, prediction_label] |
| | ) |
| | |
| | gr.Markdown("---") |
| | gr.Markdown("### 🧪 Quick Test Scenarios") |
| | |
| | with gr.Row(): |
| | gr.Markdown(""" |
| | **Scenario 1: Obvious Fraud** |
| | - Amount: $4500, Hour: 3, Dist Home: 800km |
| | - New retailer, no chip/PIN, online |
| | """) |
| | gr.Markdown(""" |
| | **Scenario 2: Normal Transaction** |
| | - Amount: $45, Hour: 14, Dist Home: 5km |
| | - Repeat retailer, chip + PIN, in-person |
| | """) |
| | gr.Markdown(""" |
| | **Scenario 3: Suspicious** |
| | - Amount: $350, Hour: 22, Dist Home: 60km |
| | - New retailer, chip but no PIN, online |
| | """) |
| | |
| | with gr.Tab("📊 Batch Predictions"): |
| | gr.Markdown("### Upload Multiple Transactions") |
| | gr.Markdown("Upload a CSV file with multiple transactions to get predictions for all of them") |
| | |
| | with gr.Row(): |
| | with gr.Column(): |
| | batch_file = gr.File(label="Upload Test CSV", file_types=[".csv"]) |
| | batch_button = gr.Button("📈 Predict Batch", variant="primary", size="lg") |
| | |
| | with gr.Column(): |
| | batch_output = gr.Markdown(label="Batch Results") |
| | download_file = gr.File(label="Download Results CSV") |
| | |
| | batch_button.click( |
| | fn=predict_batch, |
| | inputs=[batch_file], |
| | outputs=[download_file, batch_output] |
| | ) |
| | |
| | with gr.Tab("💰 Business Impact Calculator"): |
| | gr.Markdown("### Calculate Financial Impact of Your Fraud Detection Model") |
| | gr.Markdown("Enter your model's performance metrics and business parameters to see the financial impact") |
| | |
| | with gr.Row(): |
| | with gr.Column(): |
| | gr.Markdown("#### 📊 Model Performance Metrics") |
| | precision_input = gr.Slider(0, 1, step=0.01, value=0.85, label="Precision (0-1)", info="Of flagged transactions, what % are actually fraud?") |
| | recall_input = gr.Slider(0, 1, step=0.01, value=0.90, label="Recall (0-1)", info="Of all frauds, what % does the model catch?") |
| | |
| | gr.Markdown("#### 🏦 Business Parameters") |
| | total_transactions = gr.Number(label="Total Transactions per Month", value=1000000, precision=0) |
| | fraud_rate = gr.Slider(0, 10, step=0.01, value=1.0, label="Fraud Rate (%)", info="Percentage of transactions that are fraudulent") |
| | |
| | gr.Markdown("#### 💵 Cost Parameters") |
| | fraud_loss = gr.Number(label="Average Fraud Loss per Transaction ($)", value=500, precision=2) |
| | review_cost = gr.Number(label="Manual Review Cost per Flagged Transaction ($)", value=2.00, precision=2) |
| | |
| | calc_button = gr.Button("💰 Calculate Business Impact", variant="primary", size="lg") |
| | |
| | with gr.Column(): |
| | impact_output = gr.Markdown(label="Business Impact Analysis") |
| | |
| | calc_button.click( |
| | fn=calculate_business_impact, |
| | inputs=[total_transactions, fraud_rate, precision_input, recall_input, fraud_loss, review_cost], |
| | outputs=[impact_output] |
| | ) |
| | |
| | gr.Markdown("---") |
| | gr.Markdown(""" |
| | ### 📚 How to Use This Calculator |
| | |
| | **Example Scenario:** |
| | - Bank processes 1 million transactions/month |
| | - Model has 85% precision and 90% recall |
| | - 1% of transactions are fraudulent |
| | - Average fraud loss: $500 per transaction |
| | - Manual review cost: $2 per flagged transaction |
| | |
| | **What This Calculates:** |
| | 1. **True Positives:** Frauds caught by the model |
| | 2. **False Negatives:** Frauds missed (costly!) |
| | 3. **False Positives:** Legitimate transactions flagged (review costs) |
| | 4. **Net Benefit:** Total financial impact of using the model |
| | |
| | **Key Insight:** The primary benefit is the **net savings** compared to having no fraud detection system. |
| | """) |
| | |
| | with gr.Tab("📉 Model Drift Analysis"): |
| | gr.Markdown("### Analyze Model Performance Degradation") |
| | gr.Markdown("If your model's precision or recall has dropped over time, use this tool to identify likely causes and appropriate actions") |
| | |
| | with gr.Row(): |
| | with gr.Column(): |
| | gr.Markdown("#### 📊 Initial Performance (At Deployment)") |
| | initial_precision = gr.Slider(0, 1, step=0.01, value=0.85, label="Initial Precision", info="Model precision when first deployed") |
| | initial_recall = gr.Slider(0, 1, step=0.01, value=0.90, label="Initial Recall", info="Model recall when first deployed") |
| | |
| | gr.Markdown("#### 📉 Current Performance (Now)") |
| | current_precision = gr.Slider(0, 1, step=0.01, value=0.70, label="Current Precision", info="Model precision after deployment period") |
| | current_recall = gr.Slider(0, 1, step=0.01, value=0.90, label="Current Recall", info="Model recall now (may have changed)") |
| | |
| | gr.Markdown("#### ⏱️ Deployment Information") |
| | months_deployed = gr.Number(label="Months Since Deployment", value=3, precision=1, info="How long has the model been in production?") |
| | |
| | analyze_button = gr.Button("🔍 Analyze Model Drift", variant="primary", size="lg") |
| | |
| | with gr.Column(): |
| | drift_output = gr.Markdown(label="Drift Analysis & Recommendations") |
| | |
| | analyze_button.click( |
| | fn=analyze_model_drift, |
| | inputs=[initial_precision, current_precision, months_deployed, initial_recall, current_recall], |
| | outputs=[drift_output] |
| | ) |
| | |
| | gr.Markdown("---") |
| | gr.Markdown(""" |
| | ### 📚 Understanding Model Drift |
| | |
| | **What is Model Drift?** |
| | Model drift occurs when a machine learning model's performance degrades over time because the data it encounters in production differs from the data it was trained on. |
| | |
| | **Common Scenarios:** |
| | - **Precision drops from 85% to 70%** → More false positives (legitimate transactions flagged) |
| | - **Recall drops** → More frauds missed (false negatives) |
| | - **Both drop** → Model is becoming unreliable |
| | |
| | **Why It Happens:** |
| | 1. Customer behavior changes (new spending patterns, seasonal trends) |
| | 2. Fraudsters adapt their tactics |
| | 3. New products/services introduced |
| | 4. Changes in transaction processing systems |
| | 5. External factors (economic changes, regulations) |
| | |
| | **Example:** |
| | After 3 months, precision drops from 85% to 70%. This means: |
| | - Previously: 85 out of 100 flagged transactions were fraud |
| | - Now: Only 70 out of 100 flagged transactions are fraud |
| | - **30% increase in false positives** = Higher review costs, customer friction |
| | """) |
| | |
| | with gr.Tab("ℹ️ About"): |
| | gr.Markdown(""" |
| | ## About This Demo |
| | |
| | This fraud detection system uses a **Random Forest Classifier** to identify potentially fraudulent credit card transactions. |
| | |
| | ### Features Used: |
| | 1. **transaction_amount**: Transaction value in dollars |
| | 2. **transaction_hour**: Hour of day (0-23) |
| | 3. **distance_from_home_km**: Distance from cardholder's home |
| | 4. **distance_from_last_transaction_km**: Distance from previous transaction |
| | 5. **ratio_to_median_purchase**: Ratio compared to typical spending |
| | 6. **repeat_retailer**: Whether customer used this merchant before |
| | 7. **used_chip**: Whether chip card was used |
| | 8. **used_pin**: Whether PIN was entered |
| | 9. **online_order**: Whether transaction was online |
| | |
| | ### Model Performance: |
| | The model is trained to maximize **recall** (catching frauds) while maintaining reasonable **precision** (avoiding false alarms). |
| | |
| | ### Important Metrics: |
| | - **Precision**: Of flagged transactions, how many are actually fraud? |
| | - **Recall**: Of all frauds, how many do we catch? |
| | - **F1-Score**: Balance between precision and recall |
| | |
| | ### Business Impact: |
| | - **False Negative (missed fraud)**: Very costly - customer loses money |
| | - **False Positive (false alarm)**: Moderately costly - customer inconvenience |
| | |
| | --- |
| | |
| | **Created for:** AI Infinity Programme | TalentSprint |
| | **Target Audience:** Software engineers transitioning to AI roles |
| | **Educational Purpose:** Understanding classification, metrics, and business logic |
| | """) |
| |
|
| | |
| | if __name__ == "__main__": |
| | demo.launch() |