DIVYANSHI SINGH commited on
Commit
c2616da
·
1 Parent(s): cc6a90c

Feature Recovery: Restored Top Products, Pareto, Churn Probability, and CLV with fixed Plotly color attributes

Browse files
Files changed (1) hide show
  1. app.py +56 -4
app.py CHANGED
@@ -158,7 +158,7 @@ def main():
158
  values=counts.values,
159
  names=counts.index,
160
  hole=0.5,
161
- color_discrete_sequence=px.colors.sequential.Ice_r
162
  )
163
  fig.update_layout(
164
  paper_bgcolor='rgba(0,0,0,0)',
@@ -175,7 +175,7 @@ def main():
175
  fig = px.scatter(
176
  pca_df, x='PCA1', y='PCA2', color='Segment',
177
  opacity=0.6,
178
- color_discrete_sequence=px.colors.sequential.Ice_r,
179
  hover_data=[pca_df.index]
180
  )
181
  fig.update_layout(
@@ -211,6 +211,26 @@ def main():
211
  fig.update_traces(line_width=3, fill='tozeroy', fillcolor='rgba(59, 130, 246, 0.1)')
212
  st.plotly_chart(fig, use_container_width=True)
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  st.markdown("<br>", unsafe_allow_html=True)
215
  st.subheader("📥 Data Export & Actions")
216
  csv = df_filtered.to_csv().encode('utf-8')
@@ -232,6 +252,24 @@ def main():
232
  st.markdown("#### Mean Values Matrix")
233
  st.table(profile_stats.style.format(lambda x: f"£{x:,.2f}" if x > 100 else f"{x:.2f}"))
234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  elif page == "Customer Lookup":
236
  st.subheader("🔍 Intelligent Query")
237
 
@@ -258,14 +296,28 @@ def main():
258
  l3.metric("LTV GBP", f"£{cust_data['Monetary']:,.2f}")
259
 
260
  st.markdown("---")
261
- st.markdown("### 🛡️ Strategic Recommendation")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  recommendations = {
263
  "Champions": "High Value, Low Churn. Goal: Retention. Strategy: Early Access, Loyalty Rewards.",
264
  "Loyal Customers": "Consistent Value. Goal: Growth. Strategy: Cross-sell related categories.",
265
  "At-Risk": "Recent Inactivity. Goal: Re-activation. Strategy: Limited-time win-back discounts.",
266
  "Lost/Hibernating": "Historical only. Goal: Win-back or Pause. Strategy: Reactivate only high LTV types."
267
  }
268
- st.info(recommendations.get(cust_data['Segment'], "Maintain baseline engagement."))
269
 
270
  if __name__ == "__main__":
271
  main()
 
158
  values=counts.values,
159
  names=counts.index,
160
  hole=0.5,
161
+ color_discrete_sequence=px.colors.sequential.ice_r
162
  )
163
  fig.update_layout(
164
  paper_bgcolor='rgba(0,0,0,0)',
 
175
  fig = px.scatter(
176
  pca_df, x='PCA1', y='PCA2', color='Segment',
177
  opacity=0.6,
178
+ color_discrete_sequence=px.colors.sequential.ice_r,
179
  hover_data=[pca_df.index]
180
  )
181
  fig.update_layout(
 
211
  fig.update_traces(line_width=3, fill='tozeroy', fillcolor='rgba(59, 130, 246, 0.1)')
212
  st.plotly_chart(fig, use_container_width=True)
213
 
214
+ st.markdown("<br>", unsafe_allow_html=True)
215
+ st.markdown("### 📊 Revenue Concentration (Pareto)")
216
+ seg_rev = df_filtered.groupby('Segment')['Monetary'].sum().sort_values(ascending=False).reset_index()
217
+ fig_bar = px.bar(
218
+ seg_rev, x='Segment', y='Monetary',
219
+ color='Monetary',
220
+ color_continuous_scale='ice'
221
+ )
222
+ fig_bar.update_layout(paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(15, 23, 42, 0.5)', font_color="#f8fafc")
223
+ st.plotly_chart(fig_bar, use_container_width=True)
224
+
225
+ st.markdown("---")
226
+ st.subheader("🚨 Risk Analytics")
227
+ high_risk = len(df_filtered[df_filtered['Recency'] > 90])
228
+ risk_pct = (high_risk / len(df_filtered)) * 100
229
+ if risk_pct > 30:
230
+ st.warning(f"**Critical Warning**: {risk_pct:.1f}% of selected customers are churn-risk (90+ days inactive).")
231
+ else:
232
+ st.success(f"**Healthy Signal**: Retention is stable with only {risk_pct:.1f}% churn-risk.")
233
+
234
  st.markdown("<br>", unsafe_allow_html=True)
235
  st.subheader("📥 Data Export & Actions")
236
  csv = df_filtered.to_csv().encode('utf-8')
 
252
  st.markdown("#### Mean Values Matrix")
253
  st.table(profile_stats.style.format(lambda x: f"£{x:,.2f}" if x > 100 else f"{x:.2f}"))
254
 
255
+ st.markdown("---")
256
+ st.subheader("🛍️ Segment Affinity: Top 10 Products")
257
+ if os.path.exists(SEGMENT_PRODUCTS_PATH):
258
+ all_top_prods = pd.read_csv(SEGMENT_PRODUCTS_PATH)
259
+ display_segs = selected_segments[:3]
260
+ cols = st.columns(len(display_segs)) if display_segs else [st.container()]
261
+
262
+ for i, seg in enumerate(display_segs):
263
+ with cols[i]:
264
+ st.markdown(f"**{seg}**")
265
+ seg_prods = all_top_prods[all_top_prods['Segment'] == seg].head(10)
266
+ if not seg_prods.empty:
267
+ seg_prods['Description'] = seg_prods['Description'].str.slice(0, 30) + '...'
268
+ st.table(seg_prods[['Description', 'Quantity']].set_index('Description'))
269
+ else: st.info("No data.")
270
+ else:
271
+ st.info("Run product pipeline to see affinities.")
272
+
273
  elif page == "Customer Lookup":
274
  st.subheader("🔍 Intelligent Query")
275
 
 
296
  l3.metric("LTV GBP", f"£{cust_data['Monetary']:,.2f}")
297
 
298
  st.markdown("---")
299
+ st.markdown("### 🛡️ Strategic Intelligence")
300
+
301
+ ci1, ci2 = st.columns(2)
302
+ # Churn Probability Logic
303
+ avg_rec = df['Recency'].mean()
304
+ churn_prob = 1 - np.exp(-cust_data['Recency'] / (avg_rec * 1.5))
305
+ churn_pct = min(max(churn_prob * 100, 0), 100)
306
+ ci1.metric("Churn Risk Score", f"{churn_pct:.1f}%")
307
+
308
+ # Predicted CLV
309
+ avg_order = cust_data['Monetary'] / cust_data['Frequency']
310
+ projected_clv = cust_data['Monetary'] + (avg_order * cust_data['Frequency'])
311
+ ci2.metric("Projected 1Y-LTV", f"£{projected_clv:,.2f}")
312
+
313
+ st.markdown("<br>", unsafe_allow_html=True)
314
  recommendations = {
315
  "Champions": "High Value, Low Churn. Goal: Retention. Strategy: Early Access, Loyalty Rewards.",
316
  "Loyal Customers": "Consistent Value. Goal: Growth. Strategy: Cross-sell related categories.",
317
  "At-Risk": "Recent Inactivity. Goal: Re-activation. Strategy: Limited-time win-back discounts.",
318
  "Lost/Hibernating": "Historical only. Goal: Win-back or Pause. Strategy: Reactivate only high LTV types."
319
  }
320
+ st.info(f"**Execution Strategy**: {recommendations.get(cust_data['Segment'], 'Maintain baseline engagement.')}")
321
 
322
  if __name__ == "__main__":
323
  main()