Omnigraph
Graph engine for context assembly. Object-storage native. Agents work with graph data the way engineers work with code: branched, typed, reviewed, merged, audited, and governed.
Разбил клиентскую базу банка на 6 RFM-сегментов: топ-20% клиентов держат 38,2% выручки (Gini 0,324). Синтетический датасет — 1 983 клиента, 9 492 транзакции.
Translation pending
DataGitHub @NikitaBoyarkinOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
Segment bank clients by transaction behavior using Recency, Frequency, Monetary scoring
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗ _ _
.__|_._ ____.._ _.| _o _____|___|_ _.._ |___|o _ .__|_ _
| | | | |(_|| |(_||\/_>|_> (_)| |_)(_|| ||<(_||(/_| ||__>
/
╭──────────────────────────────────────────────────────────────────────────╮
│ Транзакционный лог розничного банка не даёт единой картины ценности к... │
╰──────────────────────────────────────────────────────────────────────────╯
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
RFM-сегментация 1 983 клиентов банка по 9 492 транзакциям (после отбрасывания строк с флагом аномалии): коэффициент Джини 0,324, топ-20 % клиентов дают 38,2 % выручки, средний RFM-балл — 7,50.
▶ Diagram: RFM segmentation of 1,983 bank clients — opens in a browser, no install, no build
On this page: Situation · Task · Actions · Result · Background · Method · Results · Chart gallery · Hypotheses · Recommendations · Project layout
Транзакционный лог розничного банка не даёт единой картины ценности клиента: кого стоит удерживать, кто вот-вот уйдёт и на какой сегмент направлять маркетинг. Задача — сегментировать клиентов банка по транзакционному поведению через скоринг Recency, Frequency, Monetary, сопоставить комбинации квартилей именованным сегментам и отдать результат в CSV + Excel + графиках + интерактивном дашборде.
Превратить один синтетический транзакционный лог в адресуемый сегмент для каждого клиента и доказать, что сегментация имеет бизнес-смысл, а не принять это на веру.
is_anomaly == 1.customer_id: recency, frequency, monetary_value.RFMClass и RFMScore (3..12).444 и 233 больше не делят один бакет.concentration_ratio по каждому сегменту.images/) и дашборд на Streamlit.Сегментировать клиентов банка по транзакционному поведению через скоринг Recency, Frequency, Monetary, сопоставить комбинации квартилей именованным сегментам и экспортировать CSV + Excel + графики + интерактивный дашборд.
Synthetic transaction log for 2,000 clients of a retail bank. The goal is to identify high-value clients, flag at-risk ones, and give marketing a targetable segment per customer.
generate_data.py, seed 42)customer_id, transaction_date, amount, product_category, payment_method, is_anomalyuv sync --all-extras # or: pip install -e ".[dev,dashboard]"
python generate_data.py # builds data/bank_rfm_dataset_10k_fixed.csv
python rfm_analysis.py # writes data/rfm_output.csv, data/rfm_output_report.xlsx, images/*.png
python hypotheses.py # runs the testable hypotheses over the RFM output
pytest # 54 tests — pipeline functions, README/CSV binding, dashboard smoke
streamlit run dashboard/app.py # interactive dashboard (5 tabs)
is_anomaly == 1.customer_id: recency (days since last txn vs snapshot +1d), frequency (txn count), monetary_value (sum).R_Quartile: 4 = most recent, 1 = longest agoF_Quartile: 4 = most frequent, 1 = rarestM_Quartile: 4 = highest spend, 1 = lowestRFMClass: 3-digit string (444 = best, 111 = worst); RFMScore = sum (3..12)444 and 233 no longer share a bucket:| Condition | Segment |
|---|---|
| R≥4 & F≥4 & M≥4 | Champions |
| R≥3 & F≥3 & M≥3 | Loyal |
| R≥3 & F≥2 & M≥3 | Potential Loyalists |
| R≤2 & F≥3 | At Risk |
| R≤2 & F≤2 | Hibernating |
| else | Need Attention |
concentration_ratio = revenue_share / customer_share flags over/under-indexing.data/rfm_output.csv), formatted Excel (data/rfm_output_report.xlsx), charts (images/), interactive dashboard (dashboard/).| Segment | Customers | Avg recency | Avg frequency | Avg monetary | Avg RFM |
|---|---|---|---|---|---|
| Champions | 126 | 11.35 | 8.16 | 27,608.83 | 12.00 |
| Loyal | 376 | 32.13 | 6.40 | 20,692.31 | 10.32 |
| Potential Loyalists | 79 | 32.62 | 3.97 | 16,777.17 | 8.57 |
| At Risk | 349 | 123.85 | 6.30 | 19,381.56 | 8.37 |
| Need Attention | 410 | 30.39 | 4.07 | 8,962.92 | 7.20 |
| Hibernating | 643 | 177.47 | 2.92 | 8,786.79 | 4.56 |
Mean RFM score across the base is 7.50 — exactly the midpoint of the 3–12 range. Monetary concentration: Gini = 0.324 — the top 20% of customers hold 38.2% of revenue. Champions over-index on revenue (ratio 1.91), Hibernating under-indexes (ratio 0.61).
Every chart below follows the same reading order: what it shows (description) → the chart → what it means (insights).
Description. Horizontal bar chart of customer counts per RFM segment, ordered from most to least populated. Answers the first portfolio question: how big is each cluster of the client base?
Insights.
Description. Boxplot of lifetime monetary value per customer by segment (log scale), ordered by segment median. Shows where high spenders actually live.
Insights.
Description. Scatter of every customer by recency (days since last transaction) and frequency; point size encodes monetary value, color encodes segment. The canonical RFM map in one view.
Insights.
Description. Cumulative share of revenue vs cumulative share of customers (poorest → richest). The distance from the equality diagonal is the inequality, summarized by the Gini coefficient.
Insights.
Description. Histogram of the composite RFM score (3–12) across all customers; dashed line marks the mean (7.50). A quick shape check of overall engagement health.
Insights.
Description. 4×4 grid of customer counts per (Recency × Frequency) quartile combo — the classic RFM matrix. Cell shade = count; number inside each cell = average monetary value of that cell.
Insights.
Description. Grouped horizontal bars: each segment's share of customers (%) against its share of revenue (%). A revenue bar visibly longer than the customer bar means the segment over-indexes on value.
Insights.
Description. Boxplot of average transaction value (AOV = monetary / frequency) per customer by segment, log scale. Splits "big spenders" into "few large purchases" vs "many small purchases".
Insights.
Description. Monthly revenue (top panel) and transaction count (bottom panel) by segment across the full 15-month window. Shows how each segment's activity evolves over time.
Insights.
Declarative dashboards over the same CSV outputs, built with dbt-charts (dct). No HTML/JS hand-written — each board is YAML in charts/, and every query runs against the registered CSV sources in dbt_charts.yml.
dct validate charts/ --strict # structural gate (no warehouse needed)
dct serve # live preview of every board
mkdir -p renders && dct render charts/rfm_overview.yml --format html --output renders/rfm_overview.html
| Board | What it shows |
|---|---|
charts/rfm_overview.yml | KPI row (clients, avg monetary/recency/RFM), clients per segment, avg monetary by segment, recency-vs-frequency scatter |
charts/rfm_matrix.yml | RFM score distribution, R×F quartile heatmap, top RFM classes |
charts/rfm_concentration.yml | Concentration ratio per segment, customer vs monetary share, Lorenz curve |
charts/transactions_profile.yml | Product mix, payment-channel mix, amount by product, anomaly rate by channel |
Boards carry interactive filters (segment / payment method) and render to HTML, PNG, SVG, or PDF.
Five original + three added hypotheses; five testable on this schema, three untestable. Every testable hypothesis reports both the raw and the Holm-adjusted p-value (Holm–Bonferroni across the five tests).
| # | Hypothesis | Test | Raw p | Holm p | Result |
|---|---|---|---|---|---|
| H1 | Higher Monetary ↔ more distinct products | Spearman ρ (customer level) | < 0.001 | 0.000 | ρ = 0.61 — supported |
| H5 | Mobile-bank users have higher Monetary | Mann-Whitney U, two-sided; n = 391 mobile vs 1,592 other | 0.0003 | 0.0012 | significant but the effect runs the OPPOSITE way — not supported as stated |
| H6 | Segment × product-category associated | χ² independence, customer level (dominant category); dof 25 | 0.002 (permutation) | 0.006 | χ² = 52.32, Cramér's V = 0.073 — статистически детектируемо, практически ничтожно (association есть, но actionable: false при пороге V ≥ 0,10) |
| H7 | Mobile users have lower Recency | Mann-Whitney U, two-sided | 0.43 | 0.80 | not supported |
| H8 | Large-amount flag independent of payment channel | χ² independence; dof 4 | 0.40 | — | χ² = 4.04 — independent, as expected (not rejected) |
| H2 | Low Recency → higher retention | — | — | — | untestable: no cohort panel / retention label |
| H3 | Hibernating clients reactivate via email | — | — | — | untestable: no campaign exposure data |
| H4 | High Frequency → higher NPS | — | — | — | untestable: no NPS / satisfaction field |
Reading the three surprises. H5 is statistically significant but in the wrong direction: mobile-majority customers have a lower median monetary (11,840 vs 13,445), and the groups also differ in transaction count (median frequency 4 vs 5) — a confound, so the raw comparison does not isolate channel. H7's apparent effect disappears entirely (69 vs 66 days, p = 0.43). H8 was reframed away from "anomaly rate by segment": segments are built on the anomaly-dropped frame, so dropping a transaction lowers its customer's frequency and can move them into a lower segment — a mechanical link that made the old segment comparison (Hibernating 7.5% vs Champions 2.4%) significant for reasons unrelated to amounts. Per-channel anomaly rates are flat and independent: карта 5.50%, банковский перевод 5.02%, криптовалюта 4.87%, Apple Pay 4.66%, Google Pay 4.41%. H6 is the quiet one: after the customer-level fix the test is significant (Holm p = 0.006), but Cramér's V = 0.073 is negligible — segments and product-category mix are detectably associated and useless for targeting. hypotheses.py therefore reports actionable: false, and the association should not be read as support for segment-targeted cross-sell.
Run python hypotheses.py to reproduce.
docs/experiment_winback.md).| File | What |
|---|---|
docs/data_dictionary.md | Field catalog for source + RFM tables |
docs/sql_templates.md | SQL equivalents of the pipeline (PostgreSQL/ClickHouse) |
docs/metrics_framework.md | Input→Output→Outcome, leading/lagging per segment |
docs/experiment_winback.md | A/B design for a win-back campaign (FINER, sample size) |
docs/exp001_analysis_plan.md | Pre-registered analysis plan for EXP-001 (MDE +5 pp, decision rule) |
scripts/ab_test_analyzer.py | SRM, significance, power and guardrail checks — --design, --baseline, --sensitivity, --results |
docs/prd_segment_targeting.md | PRD — expose rfm_segment to marketing |
dashboard/app.py | Streamlit dashboard (Overview / Segments / RFM map / Concentration / Raw) |
charts/*.yml | dbt-charts declarative boards (validate + render + serve), each with its own filter variables |
dbt_charts.yml | dbt-charts project config — CSV source registry |
presentation/slides.md | Marp deck summarizing the project |
generate_data.py); segment sizes and correlations reflect the generator, not a real bank.recency is computed against a snapshot date (max txn + 1 day), not today.rfm_analysis.py canonical pipeline (load -> score -> segment -> export)
generate_data.py synthetic dataset generator
hypotheses.py testable + untestable hypothesis checks
utils/ Excel report generation
dashboard/ Streamlit interactive dashboard
charts/ dbt-charts declarative YAML boards
presentation/ Marp slide deck
docs/ data dictionary, SQL templates, A/B design, PRD, metrics
tests/ pytest suite (54)
data/ dataset + outputs (gitignored where regenerable)
images/ charts
renders/ dbt-charts HTML/PNG renders (gitignored where regenerable)
notebooks/ exploratory notebooks
.github/ CI workflow (validate + test)
MIT — see LICENSE.