vistaar 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vistaar-0.3.1/LICENSE +21 -0
- vistaar-0.3.1/MANIFEST.in +24 -0
- vistaar-0.3.1/PKG-INFO +237 -0
- vistaar-0.3.1/README.md +181 -0
- vistaar-0.3.1/VISTAAR_User_Guide.md +606 -0
- vistaar-0.3.1/VISTAAR_User_Guide.pdf +0 -0
- vistaar-0.3.1/docs/branding.md +27 -0
- vistaar-0.3.1/docs/databricks.md +51 -0
- vistaar-0.3.1/docs/installation.md +70 -0
- vistaar-0.3.1/docs/methodology.md +153 -0
- vistaar-0.3.1/docs/telco_churn.md +84 -0
- vistaar-0.3.1/examples/01_quickstart.ipynb +133 -0
- vistaar-0.3.1/examples/02_segmentation.ipynb +73 -0
- vistaar-0.3.1/examples/03_shap.ipynb +82 -0
- vistaar-0.3.1/examples/04_databricks.ipynb +69 -0
- vistaar-0.3.1/examples/05_telco_churn.ipynb +189 -0
- vistaar-0.3.1/examples/VISTAAR_end_to_end.ipynb +776 -0
- vistaar-0.3.1/examples/VISTAAR_end_to_end_clean.ipynb +776 -0
- vistaar-0.3.1/pyproject.toml +71 -0
- vistaar-0.3.1/setup.cfg +4 -0
- vistaar-0.3.1/tests/test_campaigns.py +132 -0
- vistaar-0.3.1/tests/test_engine.py +271 -0
- vistaar-0.3.1/tests/test_quickstart.py +33 -0
- vistaar-0.3.1/tests/test_round2.py +259 -0
- vistaar-0.3.1/tests/test_round3.py +185 -0
- vistaar-0.3.1/tests/test_statistics.py +107 -0
- vistaar-0.3.1/tests/test_telco_patterns.py +96 -0
- vistaar-0.3.1/vistaar/__init__.py +72 -0
- vistaar-0.3.1/vistaar/anomaly/__init__.py +6 -0
- vistaar-0.3.1/vistaar/anomaly/anomaly.py +58 -0
- vistaar-0.3.1/vistaar/anomaly/drift.py +157 -0
- vistaar-0.3.1/vistaar/causal/__init__.py +5 -0
- vistaar-0.3.1/vistaar/causal/effects.py +195 -0
- vistaar-0.3.1/vistaar/conversion/__init__.py +6 -0
- vistaar-0.3.1/vistaar/conversion/opportunities.py +37 -0
- vistaar-0.3.1/vistaar/conversion/ranking.py +149 -0
- vistaar-0.3.1/vistaar/core/__init__.py +6 -0
- vistaar-0.3.1/vistaar/core/config.py +255 -0
- vistaar-0.3.1/vistaar/core/data_validator.py +149 -0
- vistaar-0.3.1/vistaar/core/engine.py +1017 -0
- vistaar-0.3.1/vistaar/core/exceptions.py +27 -0
- vistaar-0.3.1/vistaar/core/logging.py +25 -0
- vistaar-0.3.1/vistaar/core/results.py +584 -0
- vistaar-0.3.1/vistaar/customer/__init__.py +5 -0
- vistaar-0.3.1/vistaar/customer/intelligence.py +115 -0
- vistaar-0.3.1/vistaar/data/conversion_sample.csv +8013 -0
- vistaar-0.3.1/vistaar/datasets.py +339 -0
- vistaar-0.3.1/vistaar/discovery/__init__.py +9 -0
- vistaar-0.3.1/vistaar/discovery/ask.py +208 -0
- vistaar-0.3.1/vistaar/discovery/explore.py +134 -0
- vistaar-0.3.1/vistaar/discovery/guidance.py +113 -0
- vistaar-0.3.1/vistaar/discovery/insights.py +289 -0
- vistaar-0.3.1/vistaar/discovery/interactions.py +152 -0
- vistaar-0.3.1/vistaar/discovery/simpsons.py +174 -0
- vistaar-0.3.1/vistaar/explainability/__init__.py +6 -0
- vistaar-0.3.1/vistaar/explainability/feature_importance.py +246 -0
- vistaar-0.3.1/vistaar/explainability/shap_engine.py +279 -0
- vistaar-0.3.1/vistaar/funnel/__init__.py +5 -0
- vistaar-0.3.1/vistaar/funnel/funnel.py +68 -0
- vistaar-0.3.1/vistaar/monitoring/__init__.py +15 -0
- vistaar-0.3.1/vistaar/monitoring/bundle.py +130 -0
- vistaar-0.3.1/vistaar/monitoring/calibration.py +121 -0
- vistaar-0.3.1/vistaar/monitoring/monitor.py +104 -0
- vistaar-0.3.1/vistaar/predictive/__init__.py +5 -0
- vistaar-0.3.1/vistaar/predictive/classification.py +466 -0
- vistaar-0.3.1/vistaar/predictive/evaluation.py +57 -0
- vistaar-0.3.1/vistaar/predictive/metrics.py +129 -0
- vistaar-0.3.1/vistaar/predictive/prune.py +85 -0
- vistaar-0.3.1/vistaar/predictive/reasons.py +98 -0
- vistaar-0.3.1/vistaar/predictive/selection.py +238 -0
- vistaar-0.3.1/vistaar/predictive/woe.py +84 -0
- vistaar-0.3.1/vistaar/profiling/__init__.py +5 -0
- vistaar-0.3.1/vistaar/profiling/diagnostics.py +129 -0
- vistaar-0.3.1/vistaar/profiling/profiler.py +322 -0
- vistaar-0.3.1/vistaar/py.typed +0 -0
- vistaar-0.3.1/vistaar/registry.py +278 -0
- vistaar-0.3.1/vistaar/reporting/__init__.py +6 -0
- vistaar-0.3.1/vistaar/reporting/assets/hdfc_bank_logo.svg +37 -0
- vistaar-0.3.1/vistaar/reporting/exporters.py +148 -0
- vistaar-0.3.1/vistaar/reporting/html_report.py +481 -0
- vistaar-0.3.1/vistaar/reporting/theme.py +112 -0
- vistaar-0.3.1/vistaar/sampling/__init__.py +5 -0
- vistaar-0.3.1/vistaar/sampling/stratified.py +351 -0
- vistaar-0.3.1/vistaar/segmentation/__init__.py +5 -0
- vistaar-0.3.1/vistaar/segmentation/clustering.py +277 -0
- vistaar-0.3.1/vistaar/segmentation/micro_segments.py +589 -0
- vistaar-0.3.1/vistaar/segmentation/portfolio.py +150 -0
- vistaar-0.3.1/vistaar/segmentation/rule_discovery.py +185 -0
- vistaar-0.3.1/vistaar/segmentation/subgroup.py +183 -0
- vistaar-0.3.1/vistaar/spark/__init__.py +5 -0
- vistaar-0.3.1/vistaar/spark/adapter.py +146 -0
- vistaar-0.3.1/vistaar/statistics/__init__.py +28 -0
- vistaar-0.3.1/vistaar/statistics/confidence_intervals.py +178 -0
- vistaar-0.3.1/vistaar/statistics/lift.py +176 -0
- vistaar-0.3.1/vistaar/statistics/significance.py +158 -0
- vistaar-0.3.1/vistaar/targeting/__init__.py +12 -0
- vistaar-0.3.1/vistaar/targeting/campaign.py +210 -0
- vistaar-0.3.1/vistaar/targeting/decile_segments.py +136 -0
- vistaar-0.3.1/vistaar/targeting/deciles.py +127 -0
- vistaar-0.3.1/vistaar/targeting/profit.py +181 -0
- vistaar-0.3.1/vistaar/timebased/__init__.py +5 -0
- vistaar-0.3.1/vistaar/timebased/trends.py +60 -0
- vistaar-0.3.1/vistaar/uplift/__init__.py +5 -0
- vistaar-0.3.1/vistaar/uplift/models.py +295 -0
- vistaar-0.3.1/vistaar/utils/__init__.py +1 -0
- vistaar-0.3.1/vistaar/utils/helpers.py +172 -0
- vistaar-0.3.1/vistaar/utils/lazy.py +29 -0
- vistaar-0.3.1/vistaar/utils/progress.py +119 -0
- vistaar-0.3.1/vistaar/version.py +3 -0
- vistaar-0.3.1/vistaar/visualization/__init__.py +5 -0
- vistaar-0.3.1/vistaar/visualization/dashboards.py +52 -0
- vistaar-0.3.1/vistaar/visualization/plots.py +343 -0
- vistaar-0.3.1/vistaar.egg-info/PKG-INFO +237 -0
- vistaar-0.3.1/vistaar.egg-info/SOURCES.txt +115 -0
- vistaar-0.3.1/vistaar.egg-info/dependency_links.txt +1 -0
- vistaar-0.3.1/vistaar.egg-info/requires.txt +36 -0
- vistaar-0.3.1/vistaar.egg-info/top_level.txt +1 -0
vistaar-0.3.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MyDataIQ contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include pyproject.toml
|
|
4
|
+
include VISTAAR_User_Guide.md
|
|
5
|
+
include VISTAAR_User_Guide.pdf
|
|
6
|
+
recursive-include docs *.md
|
|
7
|
+
recursive-include examples *.ipynb
|
|
8
|
+
recursive-include tests *.py
|
|
9
|
+
recursive-include vistaar *.py *.csv *.svg *.typed
|
|
10
|
+
|
|
11
|
+
prune dist
|
|
12
|
+
prune uploads
|
|
13
|
+
prune reports
|
|
14
|
+
prune .venv
|
|
15
|
+
global-exclude *.html
|
|
16
|
+
global-exclude *.xlsx
|
|
17
|
+
global-exclude *.xls
|
|
18
|
+
global-exclude *.joblib
|
|
19
|
+
global-exclude *.png
|
|
20
|
+
global-exclude *.whl
|
|
21
|
+
global-exclude *.tar.gz
|
|
22
|
+
global-exclude *.pyc
|
|
23
|
+
global-exclude .DS_Store
|
|
24
|
+
recursive-exclude * __pycache__
|
vistaar-0.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vistaar
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Automated profiling, micro-segmentation, conversion lift, and model explanations for tabular data.
|
|
5
|
+
Author-email: Chinmay Anand <mail@chinmayanand.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/thechinmayanand/vistaar
|
|
8
|
+
Project-URL: Source, https://github.com/thechinmayanand/vistaar
|
|
9
|
+
Project-URL: Release, https://github.com/thechinmayanand/vistaar/releases/tag/v0.3.1
|
|
10
|
+
Keywords: analytics,segmentation,conversion,lift,shap,campaign,uplift
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: numpy>=1.24
|
|
26
|
+
Requires-Dist: pandas>=2.0
|
|
27
|
+
Requires-Dist: scipy>=1.10
|
|
28
|
+
Requires-Dist: scikit-learn>=1.3
|
|
29
|
+
Requires-Dist: statsmodels>=0.14
|
|
30
|
+
Requires-Dist: plotly>=5.18
|
|
31
|
+
Requires-Dist: openpyxl>=3.1
|
|
32
|
+
Requires-Dist: tqdm>=4.66
|
|
33
|
+
Provides-Extra: ml
|
|
34
|
+
Requires-Dist: xgboost>=2.0; extra == "ml"
|
|
35
|
+
Requires-Dist: lightgbm>=4.0; extra == "ml"
|
|
36
|
+
Requires-Dist: catboost>=1.2; extra == "ml"
|
|
37
|
+
Provides-Extra: shap
|
|
38
|
+
Requires-Dist: shap>=0.44; extra == "shap"
|
|
39
|
+
Provides-Extra: spark
|
|
40
|
+
Requires-Dist: pyspark>=3.4; extra == "spark"
|
|
41
|
+
Provides-Extra: hdbscan
|
|
42
|
+
Requires-Dist: hdbscan>=0.8.33; extra == "hdbscan"
|
|
43
|
+
Provides-Extra: all
|
|
44
|
+
Requires-Dist: xgboost>=2.0; extra == "all"
|
|
45
|
+
Requires-Dist: lightgbm>=4.0; extra == "all"
|
|
46
|
+
Requires-Dist: catboost>=1.2; extra == "all"
|
|
47
|
+
Requires-Dist: shap>=0.44; extra == "all"
|
|
48
|
+
Requires-Dist: pyspark>=3.4; extra == "all"
|
|
49
|
+
Requires-Dist: hdbscan>=0.8.33; extra == "all"
|
|
50
|
+
Provides-Extra: dev
|
|
51
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
52
|
+
Requires-Dist: nbformat>=5; extra == "dev"
|
|
53
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
54
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
55
|
+
Dynamic: license-file
|
|
56
|
+
|
|
57
|
+
# VISTAAR
|
|
58
|
+
|
|
59
|
+
VISTAAR profiles a conversion table, finds interpretable micro-segments, and reports lift, significance, and ranked opportunities. Pass a pandas or PySpark DataFrame and a binary target. The library stays local: no API key, no cloud service.
|
|
60
|
+
|
|
61
|
+
The numbers are observational. Relative lift is a segment's conversion rate divided by the overall baseline. Hypothesis tests compare the segment with its complement (everyone else), not with a baseline that includes the segment. A holdout split is used whenever the table is large enough, so the significance flag is not computed on the same rows that chose the rule. Scenario sizing is arithmetic. None of this is a causal effect.
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install vistaar
|
|
67
|
+
pip install "vistaar[all]"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Optional extras:
|
|
71
|
+
|
|
72
|
+
| Extra | What it adds |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| `shap` | SHAP explanations |
|
|
75
|
+
| `ml` | XGBoost, LightGBM, CatBoost |
|
|
76
|
+
| `hdbscan` | Density clustering |
|
|
77
|
+
| `spark` | PySpark, for machines that do not already have it |
|
|
78
|
+
| `all` | All of the above |
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install "vistaar[shap]"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Python 3.10 or newer. Core dependencies are pandas, NumPy, SciPy, scikit-learn, statsmodels, Plotly, openpyxl, and tqdm. SHAP, gradient-boosted libraries, HDBSCAN, and PySpark are imported only when you use them.
|
|
85
|
+
|
|
86
|
+
From git, with every optional extra:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install "git+https://github.com/thechinmayanand/vistaar.git#egg=vistaar[all]"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
GitHub release (wheel and sdist): https://github.com/thechinmayanand/vistaar/releases/tag/v0.3.1
|
|
93
|
+
|
|
94
|
+
From a clone, after `python -m build`:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install dist/vistaar-*.whl
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Databricks notes are in [docs/databricks.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/databricks.md). Formulas are in [docs/methodology.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/methodology.md).
|
|
101
|
+
|
|
102
|
+
## Quickstart
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import vistaar as vt
|
|
106
|
+
|
|
107
|
+
df = vt.datasets.load_conversion()
|
|
108
|
+
engine = vt.Analytics(data=df, target="converted", id_column="customer_id")
|
|
109
|
+
results = engine.run()
|
|
110
|
+
|
|
111
|
+
results.summary()
|
|
112
|
+
results.segments()
|
|
113
|
+
results.lift()
|
|
114
|
+
results.opportunities()
|
|
115
|
+
results.shap()
|
|
116
|
+
results.deciles()
|
|
117
|
+
results.campaign(strategy="mass", top_deciles=2)
|
|
118
|
+
results.campaign(strategy="precision", target_precision=0.75, min_customers=100)
|
|
119
|
+
results.plot()
|
|
120
|
+
results.export("analytics_report.html")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`run()` prints a stage bar (tqdm in a notebook or a TTY, one line per stage otherwise) and a timing summary. Pass `progress=False` to silence it. Reports and charts use the `vistaar` palette by default (navy, teal, and grey, no logo). `theme="hdfc"` opts into one built-in corporate theme. See [docs/branding.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/branding.md) and [docs/telco_churn.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/telco_churn.md).
|
|
124
|
+
|
|
125
|
+
Version 0.3.1 makes that neutral palette the default. Version 0.3 is the campaign autopilot: stratified sampling with a representativeness card, model choice on top-20% capture, a non-overlapping segment portfolio, and an audit trail of each automatic decision. Version 0.2 remains the profit cut, calibration, monitoring, registry, and uplift. The worked notebook is [examples/VISTAAR_end_to_end.ipynb](https://github.com/thechinmayanand/vistaar/blob/main/examples/VISTAAR_end_to_end.ipynb). The reference is [VISTAAR_User_Guide.md](https://github.com/thechinmayanand/vistaar/blob/main/VISTAAR_User_Guide.md).
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
inside = results.decile_segments(top_deciles=2)
|
|
129
|
+
profit = results.profit_curve(cost_per_contact=50, value_column="MonthlyCharges", value_multiplier=12)
|
|
130
|
+
results.optimal_cut(cost_per_contact=50, value_per_conversion=400)
|
|
131
|
+
calibration = results.calibration()
|
|
132
|
+
results.save_model("model.joblib")
|
|
133
|
+
loaded = vt.load_model("model.joblib")
|
|
134
|
+
loaded.monitor(new_month, actuals=new_month["churn"])
|
|
135
|
+
registry = vt.Registry("registry")
|
|
136
|
+
registry.register(results, model="catboost")
|
|
137
|
+
registry.promote(challenger, champion=champion)
|
|
138
|
+
uplift = results.uplift() # needs treatment_column= on Analytics
|
|
139
|
+
results.representativeness()
|
|
140
|
+
results.portfolio()
|
|
141
|
+
results.decisions()
|
|
142
|
+
results.reason_codes(df.head(200))
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`load_conversion()` returns a bundled synthetic table (about 8,000 customers) with a planted device × customer-type reversal, an organic × returning interaction, a confounded campaign flag, funnel steps, and leakage columns (`revenue`, `post_purchase_score`, `checkout_started`). Those leakage columns are detected and kept out of segmentation and models.
|
|
146
|
+
|
|
147
|
+
The same run also supports:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
results.conversion_opportunities()
|
|
151
|
+
results.recommendations()
|
|
152
|
+
results.explore() # ranked surprises, with the numbers attached
|
|
153
|
+
results.ask("which segments convert best?")
|
|
154
|
+
results.what_if(target_rate=0.25, definition_contains="returning")
|
|
155
|
+
engine.compare(other_df) # PSI and KS
|
|
156
|
+
engine.estimate_effect() # only if treatment_column= was set
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Individual steps: `engine.profile()`, `engine.segment()`, `engine.calculate_lift(by="device")`, `engine.find_best_conversions()`, `engine.feature_importance()`, `engine.explain_with_shap()`, `engine.detect_anomalies()`, `engine.find_interactions()`, `engine.detect_simpsons()`, `engine.generate_insights()`.
|
|
160
|
+
|
|
161
|
+
An HTML report with the same sections:
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
report = engine.create_report(
|
|
165
|
+
output="html",
|
|
166
|
+
include=["profiling", "segmentation", "lift", "opportunities", "shap", "recommendations"],
|
|
167
|
+
)
|
|
168
|
+
report.save("analytics_report.html")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`results.export` also writes `.xlsx`, `.csv` (the segment table), `.json`, `.md`, and `.png` (PNG needs `kaleido`).
|
|
172
|
+
|
|
173
|
+
## What a segment row means
|
|
174
|
+
|
|
175
|
+
| Column | Meaning |
|
|
176
|
+
| --- | --- |
|
|
177
|
+
| `conversion_rate`, `n`, `conversions` | Full-sample description of this table |
|
|
178
|
+
| `baseline_rate` | Overall conversion rate in that same table |
|
|
179
|
+
| `absolute_lift` | Segment rate minus the baseline rate |
|
|
180
|
+
| `relative_lift` | Segment rate / baseline rate |
|
|
181
|
+
| `index` | `100 * relative_lift` |
|
|
182
|
+
| `p_value`, `p_value_adjusted`, `significant` | Holdout test against the complement, then Benjamini–Hochberg, when a holdout was used |
|
|
183
|
+
| `wilson_low`, `wilson_high` | Wilson interval for the full-sample rate |
|
|
184
|
+
| `replicates` | The holdout lift has the same sign as the training lift, with enough holdout rows |
|
|
185
|
+
| `observed_excess_conversions` | `(rate - baseline) * n`. Observed contrast, not incremental conversions |
|
|
186
|
+
| `inference` | `holdout_confirmation`, `holdout_underpowered`, `in_sample_post_selection`, or `density_cluster_descriptive` |
|
|
187
|
+
|
|
188
|
+
The opportunity score is a ranking heuristic. Weights, the min-max scaling, and the 0.35 confidence penalty for non-significant segments are written on the result (`opportunity_methodology`) and in the report. `scenario_extra_conversions_to_baseline` is what the count would be if the rate moved to the baseline. It is not a forecast.
|
|
189
|
+
|
|
190
|
+
## Configuration
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
engine = vt.Analytics(
|
|
194
|
+
data=df,
|
|
195
|
+
target="converted",
|
|
196
|
+
id_column="customer_id",
|
|
197
|
+
positive_label=1, # inferred when omitted
|
|
198
|
+
value_column="cart_value", # pre-outcome value; leaked revenue is not used
|
|
199
|
+
date_column="signup_date",
|
|
200
|
+
treatment_column=None, # set this to run propensity matching
|
|
201
|
+
min_segment_size=None, # default max(50, 2% of rows)
|
|
202
|
+
max_combination_depth=2, # 1, 2, or 3
|
|
203
|
+
random_state=42,
|
|
204
|
+
test_size=0.30,
|
|
205
|
+
cv_folds=5,
|
|
206
|
+
n_bootstrap=200,
|
|
207
|
+
enable_shap=True, # skipped with a clear message if shap is absent
|
|
208
|
+
model_names=("logreg", "random_forest"),
|
|
209
|
+
spark_sample_limit=100_000,
|
|
210
|
+
llm_narrative=False, # True requires an llm_fn you supply
|
|
211
|
+
)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`llm_narrative=True` calls your function with the computed insights. The library never contacts an LLM API on its own. `results.ask()` answers from the computed tables by keyword. Pass `use_llm=True` only when `llm_fn` is set.
|
|
215
|
+
|
|
216
|
+
## Notebooks
|
|
217
|
+
|
|
218
|
+
- `examples/01_quickstart.ipynb`
|
|
219
|
+
- `examples/02_segmentation.ipynb`
|
|
220
|
+
- `examples/03_shap.ipynb`
|
|
221
|
+
- `examples/04_databricks.ipynb`
|
|
222
|
+
- `examples/05_telco_churn.ipynb` — IBM Telco churn check. Findings are in [docs/telco_churn.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/telco_churn.md). The CSV is downloaded, not vendored.
|
|
223
|
+
- `examples/VISTAAR_end_to_end.ipynb` — the 0.2 tour: deciles, segments inside the cut, profit, calibration, monitoring, champion/challenger, and Hillstrom uplift.
|
|
224
|
+
|
|
225
|
+
## Development
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
pip install -e ".[dev,shap]"
|
|
229
|
+
pytest
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The wheel build:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
python -m build
|
|
236
|
+
pip install dist/vistaar-*.whl
|
|
237
|
+
```
|
vistaar-0.3.1/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# VISTAAR
|
|
2
|
+
|
|
3
|
+
VISTAAR profiles a conversion table, finds interpretable micro-segments, and reports lift, significance, and ranked opportunities. Pass a pandas or PySpark DataFrame and a binary target. The library stays local: no API key, no cloud service.
|
|
4
|
+
|
|
5
|
+
The numbers are observational. Relative lift is a segment's conversion rate divided by the overall baseline. Hypothesis tests compare the segment with its complement (everyone else), not with a baseline that includes the segment. A holdout split is used whenever the table is large enough, so the significance flag is not computed on the same rows that chose the rule. Scenario sizing is arithmetic. None of this is a causal effect.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install vistaar
|
|
11
|
+
pip install "vistaar[all]"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Optional extras:
|
|
15
|
+
|
|
16
|
+
| Extra | What it adds |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| `shap` | SHAP explanations |
|
|
19
|
+
| `ml` | XGBoost, LightGBM, CatBoost |
|
|
20
|
+
| `hdbscan` | Density clustering |
|
|
21
|
+
| `spark` | PySpark, for machines that do not already have it |
|
|
22
|
+
| `all` | All of the above |
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install "vistaar[shap]"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Python 3.10 or newer. Core dependencies are pandas, NumPy, SciPy, scikit-learn, statsmodels, Plotly, openpyxl, and tqdm. SHAP, gradient-boosted libraries, HDBSCAN, and PySpark are imported only when you use them.
|
|
29
|
+
|
|
30
|
+
From git, with every optional extra:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install "git+https://github.com/thechinmayanand/vistaar.git#egg=vistaar[all]"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
GitHub release (wheel and sdist): https://github.com/thechinmayanand/vistaar/releases/tag/v0.3.1
|
|
37
|
+
|
|
38
|
+
From a clone, after `python -m build`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install dist/vistaar-*.whl
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Databricks notes are in [docs/databricks.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/databricks.md). Formulas are in [docs/methodology.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/methodology.md).
|
|
45
|
+
|
|
46
|
+
## Quickstart
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import vistaar as vt
|
|
50
|
+
|
|
51
|
+
df = vt.datasets.load_conversion()
|
|
52
|
+
engine = vt.Analytics(data=df, target="converted", id_column="customer_id")
|
|
53
|
+
results = engine.run()
|
|
54
|
+
|
|
55
|
+
results.summary()
|
|
56
|
+
results.segments()
|
|
57
|
+
results.lift()
|
|
58
|
+
results.opportunities()
|
|
59
|
+
results.shap()
|
|
60
|
+
results.deciles()
|
|
61
|
+
results.campaign(strategy="mass", top_deciles=2)
|
|
62
|
+
results.campaign(strategy="precision", target_precision=0.75, min_customers=100)
|
|
63
|
+
results.plot()
|
|
64
|
+
results.export("analytics_report.html")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`run()` prints a stage bar (tqdm in a notebook or a TTY, one line per stage otherwise) and a timing summary. Pass `progress=False` to silence it. Reports and charts use the `vistaar` palette by default (navy, teal, and grey, no logo). `theme="hdfc"` opts into one built-in corporate theme. See [docs/branding.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/branding.md) and [docs/telco_churn.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/telco_churn.md).
|
|
68
|
+
|
|
69
|
+
Version 0.3.1 makes that neutral palette the default. Version 0.3 is the campaign autopilot: stratified sampling with a representativeness card, model choice on top-20% capture, a non-overlapping segment portfolio, and an audit trail of each automatic decision. Version 0.2 remains the profit cut, calibration, monitoring, registry, and uplift. The worked notebook is [examples/VISTAAR_end_to_end.ipynb](https://github.com/thechinmayanand/vistaar/blob/main/examples/VISTAAR_end_to_end.ipynb). The reference is [VISTAAR_User_Guide.md](https://github.com/thechinmayanand/vistaar/blob/main/VISTAAR_User_Guide.md).
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
inside = results.decile_segments(top_deciles=2)
|
|
73
|
+
profit = results.profit_curve(cost_per_contact=50, value_column="MonthlyCharges", value_multiplier=12)
|
|
74
|
+
results.optimal_cut(cost_per_contact=50, value_per_conversion=400)
|
|
75
|
+
calibration = results.calibration()
|
|
76
|
+
results.save_model("model.joblib")
|
|
77
|
+
loaded = vt.load_model("model.joblib")
|
|
78
|
+
loaded.monitor(new_month, actuals=new_month["churn"])
|
|
79
|
+
registry = vt.Registry("registry")
|
|
80
|
+
registry.register(results, model="catboost")
|
|
81
|
+
registry.promote(challenger, champion=champion)
|
|
82
|
+
uplift = results.uplift() # needs treatment_column= on Analytics
|
|
83
|
+
results.representativeness()
|
|
84
|
+
results.portfolio()
|
|
85
|
+
results.decisions()
|
|
86
|
+
results.reason_codes(df.head(200))
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`load_conversion()` returns a bundled synthetic table (about 8,000 customers) with a planted device × customer-type reversal, an organic × returning interaction, a confounded campaign flag, funnel steps, and leakage columns (`revenue`, `post_purchase_score`, `checkout_started`). Those leakage columns are detected and kept out of segmentation and models.
|
|
90
|
+
|
|
91
|
+
The same run also supports:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
results.conversion_opportunities()
|
|
95
|
+
results.recommendations()
|
|
96
|
+
results.explore() # ranked surprises, with the numbers attached
|
|
97
|
+
results.ask("which segments convert best?")
|
|
98
|
+
results.what_if(target_rate=0.25, definition_contains="returning")
|
|
99
|
+
engine.compare(other_df) # PSI and KS
|
|
100
|
+
engine.estimate_effect() # only if treatment_column= was set
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Individual steps: `engine.profile()`, `engine.segment()`, `engine.calculate_lift(by="device")`, `engine.find_best_conversions()`, `engine.feature_importance()`, `engine.explain_with_shap()`, `engine.detect_anomalies()`, `engine.find_interactions()`, `engine.detect_simpsons()`, `engine.generate_insights()`.
|
|
104
|
+
|
|
105
|
+
An HTML report with the same sections:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
report = engine.create_report(
|
|
109
|
+
output="html",
|
|
110
|
+
include=["profiling", "segmentation", "lift", "opportunities", "shap", "recommendations"],
|
|
111
|
+
)
|
|
112
|
+
report.save("analytics_report.html")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`results.export` also writes `.xlsx`, `.csv` (the segment table), `.json`, `.md`, and `.png` (PNG needs `kaleido`).
|
|
116
|
+
|
|
117
|
+
## What a segment row means
|
|
118
|
+
|
|
119
|
+
| Column | Meaning |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| `conversion_rate`, `n`, `conversions` | Full-sample description of this table |
|
|
122
|
+
| `baseline_rate` | Overall conversion rate in that same table |
|
|
123
|
+
| `absolute_lift` | Segment rate minus the baseline rate |
|
|
124
|
+
| `relative_lift` | Segment rate / baseline rate |
|
|
125
|
+
| `index` | `100 * relative_lift` |
|
|
126
|
+
| `p_value`, `p_value_adjusted`, `significant` | Holdout test against the complement, then Benjamini–Hochberg, when a holdout was used |
|
|
127
|
+
| `wilson_low`, `wilson_high` | Wilson interval for the full-sample rate |
|
|
128
|
+
| `replicates` | The holdout lift has the same sign as the training lift, with enough holdout rows |
|
|
129
|
+
| `observed_excess_conversions` | `(rate - baseline) * n`. Observed contrast, not incremental conversions |
|
|
130
|
+
| `inference` | `holdout_confirmation`, `holdout_underpowered`, `in_sample_post_selection`, or `density_cluster_descriptive` |
|
|
131
|
+
|
|
132
|
+
The opportunity score is a ranking heuristic. Weights, the min-max scaling, and the 0.35 confidence penalty for non-significant segments are written on the result (`opportunity_methodology`) and in the report. `scenario_extra_conversions_to_baseline` is what the count would be if the rate moved to the baseline. It is not a forecast.
|
|
133
|
+
|
|
134
|
+
## Configuration
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
engine = vt.Analytics(
|
|
138
|
+
data=df,
|
|
139
|
+
target="converted",
|
|
140
|
+
id_column="customer_id",
|
|
141
|
+
positive_label=1, # inferred when omitted
|
|
142
|
+
value_column="cart_value", # pre-outcome value; leaked revenue is not used
|
|
143
|
+
date_column="signup_date",
|
|
144
|
+
treatment_column=None, # set this to run propensity matching
|
|
145
|
+
min_segment_size=None, # default max(50, 2% of rows)
|
|
146
|
+
max_combination_depth=2, # 1, 2, or 3
|
|
147
|
+
random_state=42,
|
|
148
|
+
test_size=0.30,
|
|
149
|
+
cv_folds=5,
|
|
150
|
+
n_bootstrap=200,
|
|
151
|
+
enable_shap=True, # skipped with a clear message if shap is absent
|
|
152
|
+
model_names=("logreg", "random_forest"),
|
|
153
|
+
spark_sample_limit=100_000,
|
|
154
|
+
llm_narrative=False, # True requires an llm_fn you supply
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`llm_narrative=True` calls your function with the computed insights. The library never contacts an LLM API on its own. `results.ask()` answers from the computed tables by keyword. Pass `use_llm=True` only when `llm_fn` is set.
|
|
159
|
+
|
|
160
|
+
## Notebooks
|
|
161
|
+
|
|
162
|
+
- `examples/01_quickstart.ipynb`
|
|
163
|
+
- `examples/02_segmentation.ipynb`
|
|
164
|
+
- `examples/03_shap.ipynb`
|
|
165
|
+
- `examples/04_databricks.ipynb`
|
|
166
|
+
- `examples/05_telco_churn.ipynb` — IBM Telco churn check. Findings are in [docs/telco_churn.md](https://github.com/thechinmayanand/vistaar/blob/main/docs/telco_churn.md). The CSV is downloaded, not vendored.
|
|
167
|
+
- `examples/VISTAAR_end_to_end.ipynb` — the 0.2 tour: deciles, segments inside the cut, profit, calibration, monitoring, champion/challenger, and Hillstrom uplift.
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pip install -e ".[dev,shap]"
|
|
173
|
+
pytest
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The wheel build:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
python -m build
|
|
180
|
+
pip install dist/vistaar-*.whl
|
|
181
|
+
```
|