Spaces:
Running
Running
| import xgboost as xgb | |
| import pandas as pd | |
| import shap | |
| import gradio as gr | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| # Load XGBoost Booster model | |
| loaded_model = xgb.Booster() | |
| loaded_model.load_model("xgb_fixed_final_model.json") | |
| # SHAP Explainer | |
| explainer = shap.Explainer(loaded_model) | |
| # Full mapping dictionaries | |
| deal_status_mapping = { | |
| 'Contracted': 0, 'Draft': 1, 'Proposed': 2 | |
| } | |
| division_mapping = { | |
| '[Property 1]': 0, '[Property 10]': 1, '[Property 11]': 2, '[Property 12]': 3, '[Property 13]': 4, | |
| '[Property 14]': 5, '[Property 15]': 6, '[Property 16]': 7, '[Property 17]': 8, '[Property 18]': 9, | |
| '[Property 19]': 10, '[Property 2]': 11, '[Property 20]': 12, '[Property 21]': 13, '[Property 22]': 14, | |
| '[Property 23]': 15, '[Property 24]': 16, '[Property 25]': 17, '[Property 3]': 18, '[Property 4]': 19, | |
| '[Property 5]': 20, '[Property 6]': 21, '[Property 7]': 22, '[Property 8]': 23, '[Property 9]': 24 | |
| } | |
| conference_mapping = { | |
| 'Power Four': 0, 'Group of Five': 1, 'Non-Power Four / Group of Five': 2 | |
| } | |
| geography_mapping = { | |
| 'South': 0, 'East Coast': 1, 'Midwest': 2, 'West Coast': 3, 'Mountain West': 4 | |
| } | |
| category_mapping = { | |
| 'Entitlement & Sponsorship': 0, 'Signage': 1, 'Activation': 2, 'Intellectual Property': 3, 'Miscellaneous': 4, | |
| 'Print': 5, 'Promotion': 6, 'Radio': 7, 'Tickets & Hospitality': 8, 'Television': 9, 'Experiential': 10 | |
| } | |
| product_mapping = { | |
| 'Arena Sports': 0, 'Baseball': 1, "Basketball - Men's": 2, "Basketball - Women's": 3, 'Football': 4, 'Gymnastics': 5, | |
| 'Olympic Sports': 6, 'Soccer': 7, 'Softball': 8, 'Volleyball': 9, "Lacrosse - Men's": 10, "Lacrosse - Women's": 11, | |
| "Soccer - Men's": 12, 'Hockey': 13, 'Basketball': 14, "Soccer - Women's": 15, 'Wrestling': 16, 'Lacrosse': 17 | |
| } | |
| industry_mapping = { | |
| 'Quick Serve Restaurant: Sandwich': 0, 'Consumer Electronics: Audio, Visual & Wearables': 1, 'Materials: Paper & Forest Products': 2, | |
| 'Consumer Services: Moving & Storage': 3, 'Beverage - Non-Alcoholic: Soft Drink & Carbonated': 4, 'Financial: Banking': 5, | |
| 'Financial: Credit Union': 6, 'Construction & Industrial: HVAC': 7, 'Government: Health': 8, 'Quick Serve Restaurant: Chicken': 9, | |
| 'Utilities: Services & Energy Industries (Multiline or Other)': 10, 'Apparel & Accessories: Athletic & Footwear': 11, | |
| 'Restaurant: Casual': 12, 'Campus: College/School': 13, 'Healthcare: Hospital': 14, 'Insurance: Insurance Broker': 15, | |
| 'Utilities: Electric': 16, 'Insurance: Property & Casualty': 17, 'Insurance: Life & Health': 18, | |
| 'Telecom: Integrated (TV, Internet Provider, Phone)': 19, 'Auto: Tire Manufacturer': 20, 'Auto: Regional Dealer Association (Tier 2)': 21, | |
| 'Real Estate: Properties & Developments': 22, 'Auto: Car Manufacturer (Non-US; Tier 1)': 23, 'Retail: Ticket System': 24, | |
| 'Government: Tourism': 25, 'Leisure & Recreation: Casino, Race Track, Gaming': 26, 'Auto: Dealer Group': 27, | |
| 'Auto: Car Manufacturer (Domestic/Import)': 28, 'Campus: University Department': 29, 'Beverage - Alcohol: Beer (US)': 30, | |
| 'Quick Serve Restaurant: Burger': 31, 'Apparel & Accessories: Other Accessories': 32, 'Business Services: Legal & Law Firm': 33, | |
| 'Construction & Industrial: Pest Control': 34, 'Government: Commerce & Economic': 35, 'Auto: Dealership (Tier 3)': 36, | |
| 'Technology: Software': 37, 'Quick Serve Restaurant: Mexican/Latin': 38, 'Food & Beverage Distribution: Grocery': 39, | |
| 'Quick Serve Restaurant: Other QSR': 40, 'Retail: Jewelry': 41, 'Retail: Grocery': 42, 'Auto: Dealership': 43, | |
| 'Government: Agriculture, Fish & Wildlife': 44, 'Consumer Products: CPG (Multiline or Other)': 45, 'Food Products: Snacks': 46, | |
| 'Healthcare: Orthopedics, Physical Therapy & Sports Medicine': 47, 'Construction & Industrial: Materials, Tools & Equipment': 48, | |
| 'Food Products: Meats, Poultry & Seafood': 49, 'Media: Radio': 50, 'Beverage - Alcohol: Spirits (Bourbon, Scotch, Whiskey)': 51, | |
| 'Transportation: Road & Rail': 52, 'Food & Beverage Distribution: Concessionaire & Catering': 53, 'Media: Publishing': 54, | |
| 'Retail: Other Retail': 55, 'Organizations & Groups: Collectives': 56, 'Hotel: Hotel & Resort': 57, | |
| 'Auto: Aftermarket (Parts & Equipment)': 58, 'Manufacturing: Miscellaneous Manufacturing': 59, | |
| 'Leisure & Recreation: Museums, Zoos & Entertainment Centers': 60, 'Education: Colleges & Universities': 61, | |
| 'Apparel & Accessories: Non-Athletic Apparel & Footwear': 62, 'Retail: Athletic Apparel & Sporting Goods': 63, | |
| 'Quick Serve Restaurant: Coffee & Tea': 64, 'Financial: Affinity & Credit Card': 65, 'Business Services: Marketing, PR & Sales Agencies': 66, | |
| 'Government: Armed Forces': 67, 'Business Services: Employment Services': 68, 'Financial: Investment Services': 69, | |
| 'Government: Other Government Initiatives': 70, 'Beverage - Alcohol: Spiked/Hard Seltzer': 71, | |
| 'Organizations & Groups: Other Organizations': 72, 'Healthcare: Dental Care': 73, | |
| 'Organizations & Groups: Health Causes, Charities & Associations': 74, 'Organizations & Groups: Unions & Associations': 75, | |
| 'Leisure & Recreation: Athletic Equipment': 76, 'Healthcare: Equipment, Supplies & Distribution': 77, | |
| 'Retail: Non-Athletic Apparel, Footwear & Accessories': 78, 'Organizations & Groups: Other Charities & Non-Profits': 79, | |
| 'Consumer Products: Cosmetics & Skin Care': 80, 'Food Products: Dairy & Cheeses': 81, 'Government: Transportation & Public Safety': 82, | |
| 'Consumer Services: On-Demand Delivery': 83, 'Retail: Mass Merchant & Department Stores': 84 | |
| } | |
| rate_card_mapping = { | |
| 'Seasonal': 0, 'Individual': 1 | |
| } | |
| inventory_bucket_mapping = { | |
| 'Presenting Sponsor': 0, 'Rotational Signage': 1, 'Field-Level Signage': 2, 'Concourse Signage': 3, | |
| 'Fan Engagement Area': 4, 'Scoreboard Signage': 5, 'Marketing Space': 6, 'Tabling': 7, 'Game Sponsor': 8, | |
| 'Game Entitlement': 9, 'Rights & Licensing': 10, 'Autographed Item': 11, 'Ticket': 12, 'Schedule': 13, | |
| 'Program and Guide (Print)': 14, 'Activation': 15, 'Entitlement/Sponsorship': 16, 'Spot': 17, 'Live Read': 18, | |
| 'Live Mention': 19, 'Post Season Revenue': 20, 'Feature': 21, 'Season Ticket': 22, 'Field or Event Access': 23, | |
| 'LED Ribbon Board Signage': 24, 'Parking': 25, 'Club Ticket': 26, 'Courtside Ticket': 27, 'Roster Card': 28, | |
| 'Videoboard Promotion': 29, 'In-Game Promotion': 30, 'Miscellaneous Signage': 31, 'Sideline Branding': 32, | |
| 'Sideline Signage': 33, 'Sideline Assets': 34, 'Tailgating': 35, 'Suite': 36, 'Giveaway': 37, | |
| 'PA Announcement': 38, 'Venue': 39, 'Concession Signage': 40, 'Venue Entitlement': 41, | |
| 'Photo & Meet and Greet': 42, 'Billboard': 43, 'Group Tickets': 44, 'Post Season Ticket': 45, | |
| 'Display': 46, 'Yearbook': 47, 'Program and Guide (Digital)': 48, 'On-Field Promotion': 49, | |
| 'Tour': 50, 'Poster': 51, 'Stair Sign': 52, 'Pre-Game Specialty Sponsor': 53, 'Box Ticket': 54, | |
| 'Vomitory Signage': 55, 'Trip': 56, 'Virtual Signage': 57 | |
| } | |
| def safe_convert(value, default, min_val, max_val): | |
| try: | |
| num = float(value) | |
| return max(min_val, min(num, max_val)) | |
| except (TypeError, ValueError): | |
| return default | |
| # Main prediction and SHAP function | |
| def main_func(Inventory_Bucket, Category, Product, Geography, Conference, Deal_Status, Division, Industry, Rate_Card): | |
| try: | |
| new_row = pd.DataFrame({ | |
| 'Inventory_Bucket': [inventory_bucket_mapping.get(Inventory_Bucket, -1)], | |
| 'Category': [category_mapping.get(Category, -1)], | |
| 'Product': [product_mapping.get(Product, -1)], | |
| 'Geography': [geography_mapping.get(Geography, -1)], | |
| 'Conference': [conference_mapping.get(Conference, -1)], | |
| 'Deal_Status': [deal_status_mapping.get(Deal_Status, -1)], | |
| 'Division': [division_mapping.get(Division, -1)], | |
| 'Industry': [industry_mapping.get(Industry, -1)], | |
| 'Rate_Card': [rate_card_mapping.get(Rate_Card, -1)] | |
| }).astype(float) | |
| expected_columns = ['Deal_Status', 'Division', 'Conference', 'Geography', 'Category', 'Product', 'Industry', 'Rate_Card', 'Inventory_Bucket'] | |
| new_row = new_row[expected_columns] | |
| dtest = xgb.DMatrix(new_row) | |
| log_prediction = loaded_model.predict(dtest)[0] | |
| prediction = np.expm1(log_prediction) | |
| shap_values = explainer(dtest) | |
| fig, ax = plt.subplots(figsize=(8, 4)) | |
| shap.plots.waterfall(shap_values[0], show=False) | |
| plt.tight_layout() | |
| local_plot = plt.gcf() | |
| plt.close() | |
| return f"Predicted Revenue: ${prediction:,.2f}", local_plot | |
| except Exception as e: | |
| return f"Error: {str(e)}", None | |
| # Gradio Interface | |
| def create_app(): | |
| with gr.Blocks(title="Playfly Revenue Predictor") as demo: | |
| with gr.Row(): | |
| gr.Markdown("## Playfly Revenue Predictor & Interpreter") | |
| gr.Markdown("This app predicts **revenue** based on selected inventory, category, sport, geography, and conference.") | |
| gr.Markdown("---") | |
| Inventory_Bucket = gr.Dropdown(list(inventory_bucket_mapping.keys()), label="Inventory Bucket") | |
| Category = gr.Dropdown(list(category_mapping.keys()), label="Category") | |
| Product = gr.Dropdown(list(product_mapping.keys()), label="Product") | |
| Geography = gr.Dropdown(list(geography_mapping.keys()), label="Geography") | |
| Conference = gr.Dropdown(list(conference_mapping.keys()), label="Conference") | |
| Deal_Status = gr.Dropdown(list(deal_status_mapping.keys()), label="Deal Status") | |
| Division = gr.Dropdown(list(division_mapping.keys()), label="Division") | |
| Industry = gr.Dropdown(list(industry_mapping.keys()), label="Industry") | |
| Rate_Card = gr.Dropdown(list(rate_card_mapping.keys()), label="Rate Card") | |
| label = gr.Label(label="Revenue Prediction") | |
| local_plot = gr.Plot(label="SHAP Waterfall Plot") | |
| analyze_btn = gr.Button("Analyze", elem_id="analyze_btn") | |
| analyze_btn.click( | |
| main_func, | |
| [Inventory_Bucket, Category, Product, Geography, Conference, Deal_Status, Division, Industry, Rate_Card], | |
| [label, local_plot] | |
| ) | |
| gr.Markdown("---") | |
| gr.Examples( | |
| examples=[ | |
| ["LED Ribbon Board Signage", "Signage", "Football", "South", "Power Four", "Contracted", "[Property 2]", "Retail: Athletic Apparel & Sporting Goods", "Seasonal"], | |
| ["Giveaway", "Promotion", "Basketball - Women's", "Midwest", "Group of Five", "Draft", "[Property 4]", "Healthcare: Hospital", "Individual"] | |
| ], | |
| inputs=[Inventory_Bucket, Category, Product, Geography, Conference, Deal_Status, Division, Industry, Rate_Card], | |
| outputs=[label, local_plot], | |
| fn=main_func, | |
| cache_examples=True | |
| ) | |
| return demo | |
| demo = create_app() | |
| demo.launch() | |