sony9316 commited on
Commit
d8667c2
·
verified ·
1 Parent(s): 17ba015

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -85
app.py CHANGED
@@ -153,7 +153,7 @@ def calculate_metrics(df, threshold_minutes, scope="all"):
153
  "current_problems": current_problems,
154
  "problems_solved": problems_solved,
155
  "solve_efficiency": solve_efficiency,
156
- "revenue_loss_percent": revenue_impact # Renamed for clarity
157
  }
158
 
159
  def create_threshold_analysis(df, thresholds, scope="all"):
@@ -172,7 +172,8 @@ st.markdown('<h1 class="main-header">Getaround Delay Analysis</h1>', unsafe_allo
172
 
173
  # Sidebar with controls
174
  with st.sidebar:
175
- st.image("Getaround_logo.png", width=200)
 
176
 
177
  st.markdown("## Analysis Controls")
178
 
@@ -186,7 +187,7 @@ with st.sidebar:
186
 
187
  if selected == "Threshold & Scope":
188
  st.markdown("### Settings")
189
- threshold = st.slider("Threshold (minutes)", 0, 300, 90, step=30,
190
  help="Minimum delay between consecutive rentals")
191
  scope = st.selectbox("Implementation Scope", ["all", "connect"],
192
  format_func=lambda x: "All Cars" if x == "all" else "Connect Cars Only")
@@ -378,9 +379,9 @@ elif selected == "Threshold & Scope":
378
 
379
  st.markdown("""
380
  <div class="insight-box">
381
- <strong>Revenue Loss Explanation:</strong> This represents the percentage of total rental volume that would be blocked
382
- (prevented from booking) due to insufficient gap between rentals. It's a proxy for potential revenue loss,
383
- as these blocked slots represent lost booking opportunities.
384
  </div>
385
  """, unsafe_allow_html=True)
386
 
@@ -423,9 +424,9 @@ elif selected == "Threshold & Scope":
423
  with col4:
424
  st.markdown(f"""
425
  <div class="metric-card">
426
- <h3 style="color: #9b59b6;">{current_metrics['revenue_loss_percent']:.1f}%</h3>
427
- <p>Revenue Loss</p>
428
- <small>% of total volume blocked</small>
429
  </div>
430
  """, unsafe_allow_html=True)
431
  st.caption("Formula: blocked_rentals / total_rentals * 100")
@@ -439,7 +440,7 @@ elif selected == "Threshold & Scope":
439
  # Create dual-axis chart
440
  fig = make_subplots(
441
  rows=1, cols=2,
442
- subplot_titles=("Problems Solved vs Blocked Rentals", "Efficiency vs Revenue Loss"),
443
  specs=[[{"secondary_y": True}, {"secondary_y": True}]]
444
  )
445
 
@@ -455,15 +456,15 @@ elif selected == "Threshold & Scope":
455
  row=1, col=1, secondary_y=True
456
  )
457
 
458
- # Right chart: Efficiency vs Revenue Loss
459
  fig.add_trace(
460
  go.Scatter(x=threshold_data["threshold"], y=threshold_data["solve_efficiency"],
461
  mode="lines+markers", name="Efficiency (%)", line=dict(color="blue")),
462
  row=1, col=2, secondary_y=False
463
  )
464
  fig.add_trace(
465
- go.Scatter(x=threshold_data["threshold"], y=threshold_data["revenue_loss_percent"],
466
- mode="lines+markers", name="Revenue Loss (%)", line=dict(color="orange")),
467
  row=1, col=2, secondary_y=True
468
  )
469
 
@@ -496,7 +497,7 @@ elif selected == "Threshold & Scope":
496
  **Problems Solved:** {all_metrics['problems_solved']:,}
497
  **Blocked Rentals:** {all_metrics['blocked_rentals']:,} ({all_metrics['blocked_percentage']:.1f}%)
498
  **Efficiency:** {all_metrics['solve_efficiency']:.1f}%
499
- **Revenue Loss:** {all_metrics['revenue_loss_percent']:.1f}%
500
  """)
501
 
502
  with col2:
@@ -505,7 +506,7 @@ elif selected == "Threshold & Scope":
505
  **Problems Solved:** {connect_metrics['problems_solved']:,}
506
  **Blocked Rentals:** {connect_metrics['blocked_rentals']:,} ({connect_metrics['blocked_percentage']:.1f}%)
507
  **Efficiency:** {connect_metrics['solve_efficiency']:.1f}%
508
- **Revenue Loss:** {connect_metrics['revenue_loss_percent']:.1f}%
509
  """)
510
 
511
  # Scope comparison chart
@@ -530,90 +531,73 @@ elif selected == "Threshold & Scope":
530
  st.plotly_chart(fig_scope, use_container_width=True)
531
 
532
  # Recommendations
533
- st.markdown('<div class="section-header">Recommendations</div>', unsafe_allow_html=True)
534
 
535
- # Find optimal threshold - look for efficiency/revenue loss crossover point
536
- viable_thresholds = threshold_data[
537
- (threshold_data["problems_solved"] > 0) &
538
- (threshold_data["threshold"] >= 30) &
539
- (threshold_data["threshold"] <= 150)
540
- ]
541
-
542
- if len(viable_thresholds) > 0:
543
- # Find crossover point where efficiency starts declining and revenue loss increases significantly
544
- # Look for the "knee" where efficiency curve meets revenue loss curve
545
- viable_thresholds = viable_thresholds.sort_values("threshold")
546
-
547
- # Normalize both metrics to 0-100 scale for comparison
548
- viable_thresholds["efficiency_norm"] = viable_thresholds["solve_efficiency"]
549
- viable_thresholds["revenue_loss_norm"] = viable_thresholds["revenue_loss_percent"]
550
-
551
- # Find point where efficiency is still high but revenue loss hasn't grown too much
552
- # Look for threshold where efficiency > 20% and revenue loss < 8%
553
- good_balance = viable_thresholds[
554
- (viable_thresholds["efficiency_norm"] >= 20) &
555
- (viable_thresholds["revenue_loss_norm"] <= 8.0)
556
- ]
557
-
558
- if len(good_balance) > 0:
559
- # Among balanced options, pick the one that solves most problems
560
- optimal = good_balance.sort_values("problems_solved", ascending=False).iloc[0]
561
- else:
562
- # Fallback: find best efficiency among viable options
563
- optimal = viable_thresholds.sort_values("solve_efficiency", ascending=False).iloc[0]
564
-
565
- optimal_threshold = int(optimal["threshold"])
566
- else:
567
- optimal_threshold = 90 # Sensible fallback
568
 
569
- # Scope recommendation
570
- if connect_metrics['solve_efficiency'] > all_metrics['solve_efficiency'] and connect_metrics['problems_solved'] >= all_metrics['problems_solved'] * 0.7:
571
- recommended_scope = "Connect Only"
572
- scope_reason = "Higher efficiency with most problems solved"
573
- else:
574
- recommended_scope = "All Cars"
575
- scope_reason = "Solves more problems overall"
576
 
577
  col1, col2 = st.columns(2)
578
-
579
  with col1:
580
- st.markdown(f"""
581
- <div class="recommendation-box">
582
- <h3>Recommended Threshold</h3>
583
- <h2>{optimal_threshold} minutes</h2>
584
- <p>Balances problem solving with availability impact</p>
585
- <small>Logic: Find crossover point where efficiency ≥20% and revenue loss ≤8%</small>
586
- </div>
587
- """, unsafe_allow_html=True)
588
 
589
  with col2:
590
- st.markdown(f"""
591
- <div class="recommendation-box">
592
- <h3>Recommended Scope</h3>
593
- <h2>{recommended_scope}</h2>
594
- <p>{scope_reason}</p>
595
- <small>Logic: Compare efficiency and problems solved between all cars vs connect only</small>
596
- </div>
597
- """, unsafe_allow_html=True)
598
-
599
- # Summary table
600
- st.markdown("### Key Threshold Options")
601
- summary_thresholds = [60, 90, 120, 150]
602
- summary_data = []
603
-
604
- for t in summary_thresholds:
605
  if t in threshold_data["threshold"].values:
606
  row = threshold_data[threshold_data["threshold"] == t].iloc[0]
607
- summary_data.append({
608
  "Threshold": f"{int(t)} min",
 
609
  "Problems Solved": int(row["problems_solved"]),
610
- "Blocked Rentals": int(row["blocked_rentals"]),
611
  "Efficiency": f"{row['solve_efficiency']:.1f}%",
612
- "Revenue Loss": f"{row['revenue_loss_percent']:.1f}%"
613
  })
614
 
615
- summary_df = pd.DataFrame(summary_data)
616
- st.dataframe(summary_df, use_container_width=True, hide_index=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617
 
618
  # ========== FOOTER ==========
619
  st.markdown("---")
 
153
  "current_problems": current_problems,
154
  "problems_solved": problems_solved,
155
  "solve_efficiency": solve_efficiency,
156
+ "availability_impact": revenue_impact # More accurate naming
157
  }
158
 
159
  def create_threshold_analysis(df, thresholds, scope="all"):
 
172
 
173
  # Sidebar with controls
174
  with st.sidebar:
175
+ # Logo placeholder - you can add your logo here
176
+ # st.image("logo.png", width=200) # Uncomment and add your logo file
177
 
178
  st.markdown("## Analysis Controls")
179
 
 
187
 
188
  if selected == "Threshold & Scope":
189
  st.markdown("### Settings")
190
+ threshold = st.slider("Threshold (minutes)", 0, 300, 120, step=30,
191
  help="Minimum delay between consecutive rentals")
192
  scope = st.selectbox("Implementation Scope", ["all", "connect"],
193
  format_func=lambda x: "All Cars" if x == "all" else "Connect Cars Only")
 
379
 
380
  st.markdown("""
381
  <div class="insight-box">
382
+ <strong>Availability Impact Explanation:</strong> This represents the percentage of total rental slots that would be blocked
383
+ (prevented from booking) due to insufficient gap between rentals. This affects inventory availability but doesn't
384
+ directly translate to revenue loss, as demand patterns and pricing vary significantly.
385
  </div>
386
  """, unsafe_allow_html=True)
387
 
 
424
  with col4:
425
  st.markdown(f"""
426
  <div class="metric-card">
427
+ <h3 style="color: #9b59b6;">{current_metrics['availability_impact']:.1f}%</h3>
428
+ <p>Availability Impact</p>
429
+ <small>% of rental slots blocked</small>
430
  </div>
431
  """, unsafe_allow_html=True)
432
  st.caption("Formula: blocked_rentals / total_rentals * 100")
 
440
  # Create dual-axis chart
441
  fig = make_subplots(
442
  rows=1, cols=2,
443
+ subplot_titles=("Problems Solved vs Blocked Rentals", "Efficiency vs Availability Impact"),
444
  specs=[[{"secondary_y": True}, {"secondary_y": True}]]
445
  )
446
 
 
456
  row=1, col=1, secondary_y=True
457
  )
458
 
459
+ # Right chart: Efficiency vs Availability Impact
460
  fig.add_trace(
461
  go.Scatter(x=threshold_data["threshold"], y=threshold_data["solve_efficiency"],
462
  mode="lines+markers", name="Efficiency (%)", line=dict(color="blue")),
463
  row=1, col=2, secondary_y=False
464
  )
465
  fig.add_trace(
466
+ go.Scatter(x=threshold_data["threshold"], y=threshold_data["availability_impact"],
467
+ mode="lines+markers", name="Availability Impact (%)", line=dict(color="orange")),
468
  row=1, col=2, secondary_y=True
469
  )
470
 
 
497
  **Problems Solved:** {all_metrics['problems_solved']:,}
498
  **Blocked Rentals:** {all_metrics['blocked_rentals']:,} ({all_metrics['blocked_percentage']:.1f}%)
499
  **Efficiency:** {all_metrics['solve_efficiency']:.1f}%
500
+ **Availability Impact:** {all_metrics['availability_impact']:.1f}%
501
  """)
502
 
503
  with col2:
 
506
  **Problems Solved:** {connect_metrics['problems_solved']:,}
507
  **Blocked Rentals:** {connect_metrics['blocked_rentals']:,} ({connect_metrics['blocked_percentage']:.1f}%)
508
  **Efficiency:** {connect_metrics['solve_efficiency']:.1f}%
509
+ **Availability Impact:** {connect_metrics['availability_impact']:.1f}%
510
  """)
511
 
512
  # Scope comparison chart
 
531
  st.plotly_chart(fig_scope, use_container_width=True)
532
 
533
  # Recommendations
534
+ st.markdown('<div class="section-header">Business Decision Framework</div>', unsafe_allow_html=True)
535
 
536
+ st.markdown("""
537
+ <div class="insight-box">
538
+ <strong>Key Business Question:</strong> How much availability reduction are you willing to accept to improve customer experience and reduce cancellations?
539
+ <br><br>
540
+ The decision depends on your strategic priorities:
541
+ <ul>
542
+ <li><strong>Customer Experience Focus:</strong> Higher thresholds solve more problems but reduce available booking slots</li>
543
+ <li><strong>Revenue Maximization:</strong> Lower thresholds maintain availability but allow more customer wait times</li>
544
+ <li><strong>Operational Efficiency:</strong> Consider implementation complexity (all cars vs Connect only)</li>
545
+ </ul>
546
+ </div>
547
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
548
 
549
+ # Show current trade-offs
550
+ st.markdown("### Current Settings Trade-offs")
 
 
 
 
 
551
 
552
  col1, col2 = st.columns(2)
 
553
  with col1:
554
+ st.markdown("#### Benefits")
555
+ st.write(f"• Eliminates {current_metrics['problems_solved']:,} customer wait situations")
556
+ st.write(f"• Prevents potential cancellations and complaints")
557
+ st.write(f"• Improves customer satisfaction and retention")
558
+ st.write(f"• Achieves {current_metrics['solve_efficiency']:.1f}% efficiency (problems solved per blocked slot)")
 
 
 
559
 
560
  with col2:
561
+ st.markdown("#### Costs")
562
+ st.write(f"• Blocks {current_metrics['blocked_rentals']:,} potential booking opportunities")
563
+ st.write(f"• Reduces available inventory by {current_metrics['availability_impact']:.1f}%")
564
+ st.write(f"• May impact short-term revenue growth")
565
+ st.write(f"• Requires operational changes and monitoring")
566
+
567
+ # Strategic recommendations based on different priorities
568
+ st.markdown("### Strategic Options")
569
+
570
+ # Calculate options for different thresholds
571
+ options_data = []
572
+ for t in [60, 90, 120, 150]:
 
 
 
573
  if t in threshold_data["threshold"].values:
574
  row = threshold_data[threshold_data["threshold"] == t].iloc[0]
575
+ options_data.append({
576
  "Threshold": f"{int(t)} min",
577
+ "Strategy": "Conservative" if t <= 90 else "Balanced" if t <= 120 else "Aggressive",
578
  "Problems Solved": int(row["problems_solved"]),
579
+ "Availability Impact": f"{row['availability_impact']:.1f}%",
580
  "Efficiency": f"{row['solve_efficiency']:.1f}%",
581
+ "Recommendation": "Revenue-focused" if t <= 90 else "Balanced approach" if t <= 120 else "Customer experience-focused"
582
  })
583
 
584
+ options_df = pd.DataFrame(options_data)
585
+ st.dataframe(options_df, use_container_width=True, hide_index=True)
586
+
587
+ # Final business recommendation
588
+ current_option = options_df[options_df["Threshold"] == f"{threshold} min"]
589
+ if len(current_option) > 0:
590
+ current_strategy = current_option.iloc[0]["Strategy"]
591
+ current_rec = current_option.iloc[0]["Recommendation"]
592
+
593
+ st.markdown(f"""
594
+ <div class="recommendation-box">
595
+ <h3>Current Selection: {threshold} minutes ({current_strategy} Strategy)</h3>
596
+ <p><strong>Profile:</strong> {current_rec}</p>
597
+ <p><strong>Business Impact:</strong> This threshold solves {current_metrics['problems_solved']:,} customer problems while blocking {current_metrics['availability_impact']:.1f}% of potential bookings.</p>
598
+ <p><strong>Decision Rationale:</strong> Choose this if you prioritize {"customer experience over short-term availability" if threshold >= 120 else "availability over customer experience improvements" if threshold <= 90 else "a balanced approach between customer experience and availability"}.</p>
599
+ </div>
600
+ """, unsafe_allow_html=True)
601
 
602
  # ========== FOOTER ==========
603
  st.markdown("---")