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
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.
|
| 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.
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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'],
|
| 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()
|