Amit-kr26's picture
HF Spaces deployment
c9f187d
Raw
History Blame Contribute Delete
3.17 kB
"""Customer segmentation page."""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent.parent))
import pandas as pd
import streamlit as st
from sklearn.decomposition import PCA
from sqlalchemy import text
from customer_intelligence.analytics.customers import rfm_segment_distribution
from customer_intelligence.app.components.charts import make_bar_chart, make_scatter
from customer_intelligence.db import engine
from customer_intelligence.ml.segmentation import SEGMENT_NAMES
st.title("🔢 Customer Segmentation")
SEGMENT_FEATURES = [
"recency_days", "frequency", "monetary",
"avg_order_value", "tenure_days",
]
@st.cache_data(ttl=300)
def load_segment_data():
sql = text("""
SELECT
dc.customer_unique_id,
dc.segment_label,
dc.rfm_segment,
CAST(julianday(:today) - julianday(MAX(f.order_date_id)) AS INTEGER) AS recency_days,
COUNT(DISTINCT f.order_id) AS frequency,
SUM(f.price + f.freight_value) AS monetary,
AVG(f.price + f.freight_value) AS avg_order_value,
CAST(julianday(MAX(f.order_date_id)) - julianday(MIN(f.order_date_id)) AS INTEGER) AS tenure_days
FROM fact_orders f
JOIN dim_customers dc ON f.customer_key = dc.customer_key
WHERE dc.segment_label IS NOT NULL
AND f.order_status NOT IN ('canceled', 'unavailable')
GROUP BY dc.customer_unique_id, dc.segment_label, dc.rfm_segment
LIMIT 20000
""")
from datetime import date
import pandas as pd
with engine.connect() as conn:
df = pd.read_sql(sql, conn, params={"today": str(date.today())})
df[SEGMENT_FEATURES] = df[SEGMENT_FEATURES].apply(pd.to_numeric, errors="coerce")
df = df.dropna(subset=SEGMENT_FEATURES)
return df
df = load_segment_data()
segment_counts = (
df.groupby("segment_label").size().reset_index(name="customers")
.assign(segment_name=lambda x: x["segment_label"].map(SEGMENT_NAMES))
)
col1, col2 = st.columns(2)
with col1:
st.plotly_chart(
make_bar_chart(segment_counts, x="segment_name", y="customers", title="Cluster Sizes"),
width="stretch",
)
with col2:
rfm_dist = rfm_segment_distribution(engine)
st.plotly_chart(
make_bar_chart(rfm_dist, x="rfm_segment", y="customers", title="RFM Segment Distribution"),
width="stretch",
)
st.subheader("2D PCA of Customer Clusters")
X = df[SEGMENT_FEATURES].values
pca = PCA(n_components=2, random_state=42)
coords = pca.fit_transform(X)
pca_df = pd.DataFrame({
"PC1": coords[:, 0],
"PC2": coords[:, 1],
"Cluster": df["segment_label"].map(lambda x: SEGMENT_NAMES.get(x, f"Cluster {x}")),
})
st.plotly_chart(
make_scatter(pca_df, x="PC1", y="PC2", color="Cluster",
title="Customer Clusters (PCA 2D)", opacity=0.4),
width="stretch",
)
st.subheader("Segment Profiles")
profile = df.groupby("segment_label")[SEGMENT_FEATURES].mean().round(2)
profile.index = profile.index.map(lambda x: SEGMENT_NAMES.get(x, f"Cluster {x}"))
profile.index.name = "Segment"
st.dataframe(profile, width="stretch")