rapidsegment 1.0.0__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.
- rapidsegment-1.0.0/PKG-INFO +470 -0
- rapidsegment-1.0.0/README.md +447 -0
- rapidsegment-1.0.0/pyproject.toml +39 -0
- rapidsegment-1.0.0/src/rapidsegment/__init__.py +8 -0
- rapidsegment-1.0.0/src/rapidsegment/builder.py +625 -0
- rapidsegment-1.0.0/src/rapidsegment/py.typed +0 -0
- rapidsegment-1.0.0/src/rapidsegment/scorer.py +174 -0
- rapidsegment-1.0.0/src/rapidsegment/utils/__init__.py +3 -0
- rapidsegment-1.0.0/src/rapidsegment/utils/data_loader.py +170 -0
- rapidsegment-1.0.0/src/rapidsegment/utils/on_gcp_feature_selection.py +271 -0
- rapidsegment-1.0.0/src/rapidsegment/utils/undersampler.sql +14 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: rapidsegment
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A fast, multi-segment population scoring and combinatorial heuristic rule extraction engine.
|
|
5
|
+
Author: Bishwarup Biswas
|
|
6
|
+
Author-email: Bishwarup Biswas <bishwarup1429@gmail.com>
|
|
7
|
+
Requires-Dist: duckdb>=1.5.4
|
|
8
|
+
Requires-Dist: joblib>=1.5.3
|
|
9
|
+
Requires-Dist: numpy>=2.5.1
|
|
10
|
+
Requires-Dist: optbinning>=0.21.0
|
|
11
|
+
Requires-Dist: psutil>=7.2.2
|
|
12
|
+
Requires-Dist: pyarrow>=25.0.0
|
|
13
|
+
Requires-Dist: openpyxl>=3.1.5 ; extra == 'excel'
|
|
14
|
+
Requires-Dist: google-cloud-bigquery>=3.42.2 ; extra == 'gcp'
|
|
15
|
+
Requires-Dist: prettytable>=3.18.0 ; extra == 'prettytable'
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Project-URL: Homepage, https://github.com/B2BDA/RapidSegment
|
|
18
|
+
Project-URL: Issues, https://github.com/B2BDA/RapidSegment/issues
|
|
19
|
+
Provides-Extra: excel
|
|
20
|
+
Provides-Extra: gcp
|
|
21
|
+
Provides-Extra: prettytable
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
> [!IMPORTANT]
|
|
25
|
+
> **Legal Disclaimer**
|
|
26
|
+
> This open-source software library (`RapidSegment`) is an independent, community-driven predictive analytics framework. It is **completely unaffiliated, unrelated, and not associated** with any commercial products, software-as-a-service (SaaS) platforms, trademarks, or enterprise solutions of the same or similar name found on the internet or operated by other corporations. Any overlap in nomenclature is purely coincidental.
|
|
27
|
+
|
|
28
|
+
# RapidSegment - Strategic Segmentation & Scorecard Engine
|
|
29
|
+
|
|
30
|
+
A high-performance, industrial-grade combinatorial heuristic engine and scoring framework for extracting highly predictive, mutually exclusive segments from tabular data and compiling them into optimized financial scorecards.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 1. Executive Summary
|
|
35
|
+
|
|
36
|
+
### WHAT is it?
|
|
37
|
+
|
|
38
|
+
The **Strategic Segmentation & Scorecard Engine (RapidSegment)** is an automated framework designed to solve core challenges in enterprise predictive analytics: discovering high-performing sub-populations (segments) within large feature spaces, executing high-throughput cloud feature screening, and compiling those segments into transparent, production-ready linear scoring models.
|
|
39
|
+
|
|
40
|
+
It contains four decoupled, synergistic core components:
|
|
41
|
+
|
|
42
|
+
1. **`StrategicSegmentBuilder`**: Searches feature combinations using an Apriori-inspired pruning technique and an exhaustive multi-threshold grid search to extract precise, non-overlapping rule conditions.
|
|
43
|
+
|
|
44
|
+
2. **`StrategicSegmentScore`**: Converts those rules into a vectorized scoring model by computing harmonic feature weights, executing ultra-fast linear algebra transformations, calibrating decile distributions, and exporting the results into a lightweight JSON artifact.
|
|
45
|
+
|
|
46
|
+
3. **`BigQueryFeatureSelector`**: Scales massive feature screening loops directly within Google BigQuery, evaluating Information Value (IV) and variation markers across billions of records before downloading data.
|
|
47
|
+
|
|
48
|
+
4. **`UniversalDataLoader`**: Standardizes multi-format inputs (CSV, Parquet, Arrow, Excel, and BigQuery) into optimized in-memory structures compatible with vectorized down-stream compute engines.
|
|
49
|
+
|
|
50
|
+
### WHY do we need it?
|
|
51
|
+
|
|
52
|
+
In risk management, fraud detection, and marketing analytics, engineering transparent models usually forces teams into a difficult trade-off:
|
|
53
|
+
* **The Machine Learning Pitfall**: Black-box models (e.g., XGBoost, LightGBM) surface multi-way feature interactions automatically but cannot be natively translated into transparent, hard-coded SQL logic required by legacy transaction rules engines.
|
|
54
|
+
* **The Manual Profiling Pitfall**: Manual segmentation misses non-linear intersections of three or more variables, risks severe over-fitting on small sample sizes, and frequently creates overlapping conditions where a single record qualifies for multiple rules.
|
|
55
|
+
* **The Solution**: This framework bridges the gap by combining the automated discovery power of multi-threaded algorithmic search with the execution speeds of **DuckDB** and **Num BLAS operations**, outputting pure ANSI SQL text filters and robust linear scorecards.
|
|
56
|
+
|
|
57
|
+
### HOW does it work?
|
|
58
|
+
|
|
59
|
+
The engine runs recursively through an analytical lifecycle:
|
|
60
|
+
1. **Rank Feature Significance**: Uses Information Value (IV) calculated via optimal discretization to isolate and surface the top predictive columns.
|
|
61
|
+
2. **Combinatorial Grid Search**: Pairs and triplets features using an Apriori heuristic across a hyperparameter grid of sample sizes and lift limits to find highly predictive intersections.
|
|
62
|
+
3. **Isolate and Deduplicate**: Selects the single strongest multi-way rule, translates it into production-ready SQL, and extracts the matching records using an in-memory SQL layer (`duckdb`) to guarantee absolute mutual exclusivity for subsequent iterations.
|
|
63
|
+
4. **Vectorized Weight Calculation**: Performs an O(1) table scan across the final rule cohort matrix to compute segment weights using actual lift scaled by an optimized harmonic mean formulation.
|
|
64
|
+
5. **BLAS Execution & Model Export**: Multiplies the resulting sparse input arrays against the weight vector at raw C speeds using a matrix dot-product, calibrates score deciles, and flushes the parameters to a standardized JSON schema.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 2. Statistical & Weighting Foundations
|
|
69
|
+
|
|
70
|
+
### 1. Feature Profiling: WOE & IV
|
|
71
|
+
|
|
72
|
+
Before evaluating multi-way intersections, the engine filters individual continuous and categorical features using **Weight of Evidence (WOE)** and **Information Value (IV)**.
|
|
73
|
+
|
|
74
|
+
* **WOE (Weight of Evidence)**: Measures the predictive power of an individual bin relative to the overall baseline population. It establishes how much a specific value band shifts the log-odds of an event occurring:
|
|
75
|
+
$$WOE = \ln \left( \frac{\text{Percent of Non-Events}}{\text{Percent of Events}} \right)$$
|
|
76
|
+
* **IV (Information Value)**: Summarizes the overall predictive power of the entire variable across all its discrete bins:
|
|
77
|
+
$$IV = \sum \left( \text{Percent of Non-Events} - \text{Percent of Events} \right) \times WOE$$
|
|
78
|
+
|
|
79
|
+
Variables that yield a total $IV \times 100 > 30.0$ are flagged as strong individual predictors and are automatically prioritized during rule induction loops.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
### 2. Scorecard Weight Formulation
|
|
84
|
+
|
|
85
|
+
Once rules are finalized, they are passed to the scorecard module as a matrix of binary indicator flags ($1$ if the customer satisfies the rule, $0$ otherwise). The engine calculates the mathematical weight for each segment using a combination of **Lift** and the **Harmonic Mean of Response and Capture Rates**.
|
|
86
|
+
|
|
87
|
+
For a given segment $s$:
|
|
88
|
+
* **Response Rate ($RR_s$)**: $\frac{\text{Events}_s}{\text{Total Count}_s}$
|
|
89
|
+
* **Capture Rate ($CR_s$)**: $\frac{\text{Events}_s}{\text{Total Population Events}}$
|
|
90
|
+
* **Lift ($L_s$)**: $\frac{RR_s}{\text{Baseline Population Event Rate}}$
|
|
91
|
+
|
|
92
|
+
The engine derives the balance between structural segment density (capture rate) and vertical risk concentration (response rate) by computing their harmonic mean:
|
|
93
|
+
$$\text{Harmonic Mean}_s = 2 \times \left( \frac{RR_s \times CR_s}{RR_s + CR_s} \right)$$
|
|
94
|
+
|
|
95
|
+
This metric is multiplied by the segment's lift and scaled to produce a robust, integer-rounded operational weight:
|
|
96
|
+
$$\text{Raw Weight}_s = L_s \times \text{Harmonic Mean}_s \times 100.0$$
|
|
97
|
+
$$\text{Weight}_s = \lfloor \text{round}(\text{Raw Weight}_s) \rfloor$$
|
|
98
|
+
|
|
99
|
+
#### Decile Calculation
|
|
100
|
+
|
|
101
|
+
* Calculate and Sort Final Scores: For each customer, sum up the weights of all the segments they triggered to calculate their total score. Line up all customers and sort them by this final score in descending order (highest score to lowest score).
|
|
102
|
+
* Divide the Population Equally: Split the sorted list of customers into 10 perfectly equal groups (buckets). For example, if you have 10,000 customers, each decile bucket will contain exactly 1,000 customers..
|
|
103
|
+
* Identify the Boundary Row: For each decile band (1 through 10), look at the very last customer sitting at the bottom of that specific bucket.
|
|
104
|
+
* Assign the Minimum Threshold: Capture that customer's score and assign it as the decile minimum threshold. This score represents the lowest value required to qualify for that specific decile tier.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
### 3. Zero-Inflation & Active Population Calibration
|
|
109
|
+
|
|
110
|
+
Real-world behavioral datasets frequently exhibit high zero-inflation, where the vast majority of records fail to trigger any specialized rules.
|
|
111
|
+
|
|
112
|
+
To prevent highly skewed zero-bins from distorting score calibrations, the engine calculates the dataset's **Zero-Inflation Rate**:
|
|
113
|
+
$$\text{Zero-Inflation Rate} = 1.0 - \text{Baseline Population Event Rate}$$
|
|
114
|
+
|
|
115
|
+
* **Normal Distribution (< 80% Zero-Inflation)**: If the zero-inflation rate is low, the engine computes decile minimum score thresholds across the entire population.
|
|
116
|
+
* **High Zero-Inflation ($\ge$ 80% Zero-Inflation)**: If the zero-inflation rate meets or exceeds the 80% threshold, the engine automatically runs a Num boolean slicing mask to isolate the **Active Population** (`train_scores > 0`). Decile step-boundaries are then calibrated exclusively over this active subgroup, preventing a large block of unsegmented records from flattening the model's risk stratification tiers.
|
|
117
|
+
|
|
118
|
+
## 3. Algorithmic Design: Apriori Pruning & Grid Search
|
|
119
|
+
|
|
120
|
+
Evaluating multidimensional feature intersections across wide schemas risks severe processing delays and combinatorial explosion. This framework addresses these bottlenecks by pairing a multi-core **Apriori pruning heuristic** with a **Champion-Challenger Grid Search** architecture.
|
|
121
|
+
|
|
122
|
+
### 1. Apriori-Style Dimensional Pruning
|
|
123
|
+
|
|
124
|
+
If you evaluate combinations up to 3 dimensions deep across the top 20 predictive variables, a standard brute-force grid search must calculate every mathematical combination:
|
|
125
|
+
* **1-Way Checks**: 20 aggregations
|
|
126
|
+
* **2-Way Checks**: $\binom{20}{2} = 190$ aggregations
|
|
127
|
+
* **3-Way Checks**: $\binom{20}{3} = 1,140$ aggregations
|
|
128
|
+
* **Total Evaluated Configurations**: **1,350 aggregations** *per iteration*.
|
|
129
|
+
|
|
130
|
+
The engine cuts down this search space by leveraging the Apriori property: *If a single feature path fails to meet a performance threshold, any higher-order combination containing that path is guaranteed to fail.*
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
[Top 20 Ranked Features] ──► [Level 1: 1-Way Check] ──► (Only 6 Features Pass Floors)
|
|
134
|
+
│
|
|
135
|
+
▼
|
|
136
|
+
[Level 2: 2-Way Check] ──► (Only pairs formed from those 6 evaluated: 15 pairs)
|
|
137
|
+
│
|
|
138
|
+
▼
|
|
139
|
+
[Level 3: 3-Way Check] ──► (Only triplets where ALL internal pairs passed evaluated)
|
|
140
|
+
```
|
|
141
|
+
This pruning mechanism reduces multi-key grouping evaluations by up to 90%, speeding up execution while ensuring higher-order 3-way rules represent stable, statistically sound relationships rather than random noise in tiny data subsets.
|
|
142
|
+
|
|
143
|
+
### 2. Multi-Threshold Grid Search
|
|
144
|
+
|
|
145
|
+
When extracting rules, the engine natively accepts an execution hyperparameter matrix (param_grid) tracking lists of min_sample_size and min_lift constraints.
|
|
146
|
+
```thon
|
|
147
|
+
param_grid = {
|
|
148
|
+
"min_sample_size": [1000, 5000, 10000],
|
|
149
|
+
"min_lift": [1.5, 2.0, 2.5]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
Instead of short-circuiting early or requiring inputs to be sorted from highest to lowest threshold, the engine uses an exhaustive execution lifecycle:
|
|
153
|
+
1. **Permutation Generation**: It maps every parameter permutation into isolated, independent experiments via itertools.product.
|
|
154
|
+
2. **Exhaustive Evaluation**: For each iteration, it runs the entire multi-level Apriori combination loop for every hyperparameter combination, collecting the top rule that cleared that specific experiment's floor into a master grid_candidates array.
|
|
155
|
+
3. **Global Champion Resolution**: Once all experiments finish, the complete candidate table is sorted globally across all dimensions:
|
|
156
|
+
```thon
|
|
157
|
+
grid_candidates.sort(key=lambda x: (x["lift"], x["count"], x["rate"]), reverse=True)
|
|
158
|
+
```
|
|
159
|
+
4. **Winning Extraction**: The record at index zero (iloc[0]) is crowned the absolute champion for that loop. The engine locks in its specific rule, updates feature usage metrics, tracks the applied parameters, and isolates the target cohort.
|
|
160
|
+
---
|
|
161
|
+
* ## 4. System Architecture & Process Flow
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
[Raw Tabular Dataset Input]
|
|
165
|
+
│
|
|
166
|
+
▼
|
|
167
|
+
┌───────────────────────────────┐
|
|
168
|
+
│ Compute Feature IV Rankings │
|
|
169
|
+
└───────────────────────────────┘
|
|
170
|
+
│
|
|
171
|
+
▼
|
|
172
|
+
┌───────────────────────────────┐
|
|
173
|
+
│ Optimal Monotonic Binning │
|
|
174
|
+
└───────────────────────────────┘
|
|
175
|
+
│
|
|
176
|
+
┌────────────────┴────────────────┐
|
|
177
|
+
▼ ▼
|
|
178
|
+
[Apriori Pruning Layers] [Multi-Threshold Grid Search]
|
|
179
|
+
• Level 1: Filter 1-Way Base • Generates all size/lift combinations
|
|
180
|
+
• Level 2: Construct 2-Way Pairs • Runs experiments via parallel loops
|
|
181
|
+
• Level 3: Form valid triplets • Gathers candidate rule sets
|
|
182
|
+
└────────────────┬────────────────┘
|
|
183
|
+
│
|
|
184
|
+
▼
|
|
185
|
+
┌───────────────────────────────┐
|
|
186
|
+
│ Global Champion Selection │ ◄── Sorts by actual Lift & Volume
|
|
187
|
+
└───────────────────────────────┘
|
|
188
|
+
│
|
|
189
|
+
┌────────────────┴────────────────┐
|
|
190
|
+
▼ ▼
|
|
191
|
+
┌─────────────────────────┐ ┌─────────────────────────┐
|
|
192
|
+
│ Parse Rule to Pure SQL │ │ Residual Filter Block │
|
|
193
|
+
│ (IN, AND, Range Clauses)│ │ (DuckDB In-Memory Scan) │
|
|
194
|
+
└─────────────────────────┘ └─────────────────────────┘
|
|
195
|
+
│
|
|
196
|
+
▼
|
|
197
|
+
[Loop to Next Segment Iteration]
|
|
198
|
+
│
|
|
199
|
+
(Once Segment Pool completes)
|
|
200
|
+
│
|
|
201
|
+
▼
|
|
202
|
+
┌───────────────────────────────┐
|
|
203
|
+
│ Scorecard Engine Initialization│
|
|
204
|
+
└───────────────────────────────┐
|
|
205
|
+
│
|
|
206
|
+
▼
|
|
207
|
+
┌───────────────────────────────┐
|
|
208
|
+
│ Single-Pass DuckDB Aggregation│ ◄── Extracts population/event counts
|
|
209
|
+
└───────────────────────────────┐
|
|
210
|
+
│
|
|
211
|
+
▼
|
|
212
|
+
┌───────────────────────────────┐
|
|
213
|
+
│ Weight Compilation Matrix │ ◄── Scaled via Harmonic Mean equations
|
|
214
|
+
└───────────────────────────────┐
|
|
215
|
+
│
|
|
216
|
+
▼
|
|
217
|
+
┌───────────────────────────────┐
|
|
218
|
+
│ BLAS Matrix Dot-Product Opt │ ◄── Array @ Vector at raw C speeds
|
|
219
|
+
└───────────────────────────────┐
|
|
220
|
+
│
|
|
221
|
+
▼
|
|
222
|
+
┌───────────────────────────────┐
|
|
223
|
+
│ Decile Threshold Calibration │ ◄── Auto-isolates active pop if >= 80%
|
|
224
|
+
└───────────────────────────────┐
|
|
225
|
+
│
|
|
226
|
+
▼
|
|
227
|
+
[Final JSON Model Model Export]
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Batch 3: Parameter & Attribute Reference
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
## 5. Class Attributes & Parameter Reference
|
|
235
|
+
|
|
236
|
+
### 1. `UniversalDataLoader`
|
|
237
|
+
|
|
238
|
+
Standardizes multiple ingestion pathways into a uniform, memory-optimized PyArrow data frame abstraction.
|
|
239
|
+
|
|
240
|
+
#### Initialization Parameters
|
|
241
|
+
|
|
242
|
+
| Parameter | Type | Default | Description |
|
|
243
|
+
| --- | --- | --- | --- |
|
|
244
|
+
| `project_id` | `str` | `None` | Google Cloud project location (for BigQuery streaming). |
|
|
245
|
+
| `dataset_id` | `str` | `None` | Target BigQuery Dataset identifier. |
|
|
246
|
+
| `table_id` | `str` | `None` | Target BigQuery Table identifier. |
|
|
247
|
+
| `file_path` | `str` | `None` | Local folder system pointer path (`.csv`, `.parquet`, `.xlsx`, `.feather`). |
|
|
248
|
+
|
|
249
|
+
### 2. `StrategicSegmentBuilder`
|
|
250
|
+
|
|
251
|
+
#### Initialization Parameters
|
|
252
|
+
|
|
253
|
+
| Parameter | Type | Default | Description |
|
|
254
|
+
| :--- | :--- | :--- | :--- |
|
|
255
|
+
| `target` | `str` | *Required* | Dependent binary target column name (`1` = Event, `0` = Non-Event). |
|
|
256
|
+
| `n_jobs` | `int` | `-1` | CPU threads for parallel processing. `-1` uses `available_cores - 1`. |
|
|
257
|
+
| `min_sample_size` | `int` | `1000` | Absolute minimum record volume floor required to validate a rule. |
|
|
258
|
+
| `min_lift` | `float` | `2.0` | Minimum lift cutoff value ($\text{Segment Rate} / \text{Base Rate}$). |
|
|
259
|
+
| `min_events` | `float` | `5.0` | Absolute minimum event record volume floor required to validate a rule. |
|
|
260
|
+
| `top_n_vars` | `int` | `20` | Total highest-IV features passed into the combinatorial engine. |
|
|
261
|
+
| `max_segments` | `int` | `10` | Hard stopping ceiling for total extracted mutually exclusive segments. |
|
|
262
|
+
| `max_feature_reuse` | `int` | `1` | Max times an individual feature can appear across all final rules. |
|
|
263
|
+
| `enable_diversity` | `bool` | `False` | If `True`, blocks combinations pairing features within the same business group. |
|
|
264
|
+
| `enable_1way` | `bool` | `True` | Allows or blocks 1-dimensional rules in the final candidate pool. |
|
|
265
|
+
| `enable_2way` | `bool` | `True` | Allows or blocks 2-dimensional intersection rules in the final pool. |
|
|
266
|
+
| `enable_3way` | `bool` | `True` | Allows or blocks 3-dimensional intersection rules in the final pool. |
|
|
267
|
+
| `feature_groups` | `Dict` | `None` | Maps descriptive business category keys to groups of column strings. |
|
|
268
|
+
| `ignore_features` | `List` | `None` | Explicit list of metadata columns to drop before running processing steps. |
|
|
269
|
+
|
|
270
|
+
#### Generated Output Fields (Segment Dataframe)
|
|
271
|
+
|
|
272
|
+
* **`segment_id`**: Sequential iteration integer index.
|
|
273
|
+
* **`rule_string`**: Raw rule syntax returned by the OptBinning transformation layer.
|
|
274
|
+
* **`sql_filter`**: Standardized production-ready ANSI SQL WHERE clause condition.
|
|
275
|
+
* **`count`**: Actual volume of records matching the rule criteria.
|
|
276
|
+
* **`rate`**: Internal event frequency percentage observed inside the segment.
|
|
277
|
+
* **`lift`**: Calculated performance lift multiplier relative to the global population rate.
|
|
278
|
+
* **`meta_applied_sample_size`**: The specific `min_sample_size` parameter that captured the winning rule.
|
|
279
|
+
* **`meta_applied_min_lift`**: The specific `min_lift` parameter that captured the winning rule.
|
|
280
|
+
|
|
281
|
+
#### Diagnostic & Audit Trail Methods
|
|
282
|
+
|
|
283
|
+
**`explain_feature_journey(feature_name: str)`**: Prints an execution audit trail tracking the targeted feature across all execution loops. Details its dynamic IV, previous usage count, structural status flags (e.g., Excluded, Eligible), and whether it was adopted by a winning segment.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### 3. `StrategicSegmentScore`
|
|
288
|
+
|
|
289
|
+
#### Initialization Parameters
|
|
290
|
+
|
|
291
|
+
| Parameter | Type | Description |
|
|
292
|
+
| :--- | :--- | :--- |
|
|
293
|
+
| `target_col` | `str` | Name of the dependent binary target column (`1` = Event, `0` = Non-Event). |
|
|
294
|
+
| `primary_key` | `str` | Row-level tracking key or transaction sequence identifier string. |
|
|
295
|
+
| `segment_cols` | `List[str]` | List of compiled binary segment indicator columns ($1$ or $0$) to build into the scorecard. |
|
|
296
|
+
|
|
297
|
+
#### Exported JSON Model Artifact Schema
|
|
298
|
+
|
|
299
|
+
* **`model_metadata`**: Holds population execution records (`total_training_population`, `active_scored_population`, `active_population_pct`, `baseline_event_rate`).
|
|
300
|
+
* **`segment_weights`**: Nested dictionary mapping each column to its `weight`, `lift`, `response_rate`, and `capture_rate`.
|
|
301
|
+
* **`decile_min_thresholds`**: Dictionary mapping decile levels (`"1"` to `"10"`) to their corresponding integer score cutoffs.
|
|
302
|
+
|
|
303
|
+
### 4. `BigQueryFeatureSelector`
|
|
304
|
+
|
|
305
|
+
Designed for enterprise-scale pre-screening loops. It calculates naive IV distributions and filters variance boundaries natively inside Google BigQuery to prevent local memory bottlenecks.
|
|
306
|
+
|
|
307
|
+
#### Initialization Parameters
|
|
308
|
+
|
|
309
|
+
| Parameter | Type | Default | Description |
|
|
310
|
+
| --- | --- | --- | --- |
|
|
311
|
+
| `project_id` | `str` | `Required` | Google Cloud Platform Project identifier. |
|
|
312
|
+
| `dataset_id` | `str` | `Required` | Target BigQuery Dataset namespace. |
|
|
313
|
+
| `table_id` | `str` | `Required` | Target BigQuery Data Table identity string. |
|
|
314
|
+
| `target_column` | `str` | `Required` | Dependent binary tracking variable (1 or 0). |
|
|
315
|
+
| `iv_threshold` | `float` | `0.02` | Minimum Information Value needed to keep a feature. |
|
|
316
|
+
| `stddev_threshold` | `float` | `1e-5` | Minimum standard deviation needed to prevent zero-variance processing. |
|
|
317
|
+
| `min_bin_n_event` | `int` | `1` | Defensive baseline floor for positive items inside an individual bin. |
|
|
318
|
+
| `bins` | `int` | `10` | Quantile groupings (NTILE) used to build numeric range limits. |
|
|
319
|
+
| `batch_size` | `int` | `15` | Maximum number of column structures processed per BigQuery execution hit. |
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
## 6. Quick Start Guide
|
|
324
|
+
|
|
325
|
+
### 1. Installation
|
|
326
|
+
You can install RapidSegment directly from PyPI using either standard pip or the high-performance uv virtual environment package manager:
|
|
327
|
+
```bash
|
|
328
|
+
pip install rapidsegment
|
|
329
|
+
```
|
|
330
|
+
or
|
|
331
|
+
```bash
|
|
332
|
+
uv pip install rapidsegment
|
|
333
|
+
```
|
|
334
|
+
### 2. Get Started
|
|
335
|
+
This guide demonstrates an end-to-end analytical pipeline: extracting rules across a hyperparameter grid, evaluating cascading database coverage, generating binary indicator flags, and building an optimized scorecard.
|
|
336
|
+
|
|
337
|
+
```Python
|
|
338
|
+
import numpy as np
|
|
339
|
+
import pandas as pd
|
|
340
|
+
import duckdb
|
|
341
|
+
from RapidSegment import StrategicSegmentBuilder, StrategicSegmentScore, UniversalDataLoader
|
|
342
|
+
|
|
343
|
+
# 1. Generate Synthetic Tabular Transaction Pool for Verification
|
|
344
|
+
np.random.seed(42)
|
|
345
|
+
n_records = 50000
|
|
346
|
+
|
|
347
|
+
data = pd.DataFrame({
|
|
348
|
+
"cust_id": [f"CUST_{i:05d}" for i in range(n_records)],
|
|
349
|
+
"max_dpd_12m": np.random.choice([0, 15, 30, 60, 90], size=n_records, p=[0.7, 0.15, 0.08, 0.05, 0.02]),
|
|
350
|
+
"utilization_avg_3m": np.random.uniform(0.0, 1.2, size=n_records),
|
|
351
|
+
"spend_avg_6m": np.random.exponential(scale=3000, size=n_records),
|
|
352
|
+
"payment_ratio_3m": np.random.uniform(0.0, 1.0, size=n_records),
|
|
353
|
+
"risk_segment": np.random.choice(["Low", "Medium", "High"], size=n_records, p=[0.6, 0.3, 0.1]),
|
|
354
|
+
"default_flag": np.random.choice([0, 1], size=n_records, p=[0.95, 0.05]) # 5% baseline rate
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
# Inject structured high-risk rules to verify engine extraction
|
|
358
|
+
high_risk_mask = (data["max_dpd_12m"] >= 60) & (data["utilization_avg_3m"] >= 0.85)
|
|
359
|
+
data.loc[high_risk_mask, "default_flag"] = np.random.choice([0, 1], size=high_risk_mask.sum(), p=[0.2, 0.8])
|
|
360
|
+
|
|
361
|
+
# 2. Configure Domain Knowledge Feature Groups
|
|
362
|
+
business_groups = {
|
|
363
|
+
"delinquency_metrics": ["max_dpd_12m", "risk_segment"],
|
|
364
|
+
"utilization_metrics": ["utilization_avg_3m"],
|
|
365
|
+
"transaction_metrics": ["spend_avg_6m", "payment_ratio_3m"]
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
# 3. Define Multi-Threshold Hyperparameter Grid
|
|
369
|
+
grid_config = {
|
|
370
|
+
"min_sample_size": [1000, 2500, 5000],
|
|
371
|
+
"min_lift": [2.0, 3.5, 5.0]
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
# 4. Initialize and Run the Segment Extraction Engine
|
|
375
|
+
builder = StrategicSegmentBuilder(
|
|
376
|
+
target="default_flag",
|
|
377
|
+
top_n_vars=15,
|
|
378
|
+
max_segments=5,
|
|
379
|
+
max_feature_reuse=1,
|
|
380
|
+
param_grid=grid_config,
|
|
381
|
+
enable_diversity=True,
|
|
382
|
+
feature_groups=business_groups,
|
|
383
|
+
ignore_features=["cust_id"]
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
print("Executing recursive multi-threshold segment search...")
|
|
387
|
+
segments_summary = builder.extract_segments(data)
|
|
388
|
+
|
|
389
|
+
# Convert list of dicts to DataFrame for clean terminal output profiling
|
|
390
|
+
segments_df = pd.DataFrame(segments_summary)
|
|
391
|
+
print("\nExtracted Segment Profiles:")
|
|
392
|
+
print(segments_df[["segment_id", "count", "lift", "meta_applied_sample_size", "sql_filter"]])
|
|
393
|
+
|
|
394
|
+
# [Diagnostic Step] Print audit trail for a key feature
|
|
395
|
+
builder.explain_feature_journey("max_dpd_12m")
|
|
396
|
+
|
|
397
|
+
# 5. Review Cascading Portfolio Coverage Analysis Report
|
|
398
|
+
coverage_report = builder.evaluate_final_coverage(data)
|
|
399
|
+
print("\nCascading Portfolio Coverage Analysis:")
|
|
400
|
+
print(pd.DataFrame(coverage_report))
|
|
401
|
+
|
|
402
|
+
# 6. Prepare Binary Array Representation for Scorecard Tuning
|
|
403
|
+
scoring_df = data[["cust_id", "default_flag"]].copy()
|
|
404
|
+
|
|
405
|
+
# Map SQL filters to binary columns (1 = matches rule, 0 = otherwise)
|
|
406
|
+
segment_columns = []
|
|
407
|
+
for segment in segments_summary:
|
|
408
|
+
seg_id = segment["segment_id"]
|
|
409
|
+
sql_cond = segment["sql_filter"]
|
|
410
|
+
col_name = f"SEGMENT_{seg_id}"
|
|
411
|
+
|
|
412
|
+
# Query via DuckDB to apply pure SQL strings directly to the dataframe
|
|
413
|
+
matched_ids = duckdb.query(f"SELECT cust_id FROM data WHERE {sql_cond}").df()["cust_id"]
|
|
414
|
+
scoring_df[col_name] = scoring_df["cust_id"].isin(matched_ids).astype(int)
|
|
415
|
+
segment_columns.append(col_name)
|
|
416
|
+
|
|
417
|
+
# 7. Execute High-Throughput Scorecard Matrix Engine
|
|
418
|
+
scorecard_engine = StrategicSegmentScore(
|
|
419
|
+
target_col="default_flag",
|
|
420
|
+
primary_key="cust_id",
|
|
421
|
+
segment_cols=segment_columns
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
print("\nCompiling scorecard weights and decile thresholds...")
|
|
425
|
+
model_parameters = scorecard_engine.calculate_and_export_weights(
|
|
426
|
+
data=scoring_df,
|
|
427
|
+
export_path="production_scorecard_model.json"
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
print("\nModel Metadata Summary:")
|
|
431
|
+
print(model_parameters["model_metadata"])
|
|
432
|
+
|
|
433
|
+
print("\nCalibrated Score Decile Thresholds:")
|
|
434
|
+
for decile, min_score in model_parameters["decile_min_thresholds"].items():
|
|
435
|
+
print(f"Decile {decile:2s} -> Minimum Passing Score: {min_score}")
|
|
436
|
+
```
|
|
437
|
+
## 7. Notes
|
|
438
|
+
|
|
439
|
+
### 1. Why can't we produce OR-based rules?
|
|
440
|
+
|
|
441
|
+
Allowing OR operations within the search layer causes a massive combinatorial explosion that makes algorithmic pruning impossible. The engine relies on the Apriori property (an AND intersection), where a higher-order rule can be safely skipped if its lower-order components fail the baseline performance thresholds. If OR logic is introduced, a higher-order combination could still clear the threshold even if its individual parts fail, completely breaking the pruning heuristic and forcing an exhaustive, computationally prohibitive search.
|
|
442
|
+
|
|
443
|
+
Additionally, while single multi-way rules can handle internal OR states for categorical fields (implemented via SQL IN clauses), introducing cross-variable OR conditions natively within the same step complicates the sequential deletion process, making it much harder to cleanly extract distinct, high-risk populations.
|
|
444
|
+
|
|
445
|
+
The OR Mutually Exclusive Clarification: Technically, an OR rule could be forced to be mutually exclusive if you deleted anyone who met any part of the OR condition. The real problem with OR is that it breaks the Apriori pruning math. If Rule A fails and Rule B fails, Rule A AND Rule B is guaranteed to fail (Apriori works). But Rule A OR Rule B might succeed, meaning you can no longer drop failed features from your search space.
|
|
446
|
+
|
|
447
|
+
### 2. Why is Segment $n+k$ (e.g., Segment 3) sometimes better than Segment $n$ (e.g., Segment 2) in terms of lift or other KPIs when evaluated on the full dataset?
|
|
448
|
+
|
|
449
|
+
The segment extraction process is entirely sequential and operates on a shrinking residual population. Once a champion rule is discovered, its matching records are deleted from the working environment before the next iteration begins.
|
|
450
|
+
Because of this cascading extraction:
|
|
451
|
+
**`Local Optimization`**: The engine optimizes parameters and evaluates candidates based purely on the residual portfolio left behind by previous segments. A rule that yields massive lift on a specific, purified subset of data might look less dominant if it had been evaluated against the noisy baseline of the entire original population.
|
|
452
|
+
**`Changing Base Rates`**: As high-risk or high-performing records are stripped away in early rounds, the baseline event rate of the remaining pool shifts dynamically. This shifting baseline changes the mathematical benchmark for what constitutes a "high-lift" rule during that specific loop. Consequently, when evaluate_final_coverage maps all rules simultaneously back over the original, unfiltered dataset, the global KPIs can naturally surface instances where a later segment outperforms an earlier one.
|
|
453
|
+
|
|
454
|
+
### 3. My dataset is not zero inflated, still my deciles 3 onwards the floor is zero?
|
|
455
|
+
|
|
456
|
+
This happens when your extraction criteria are so restrictive that your final segments capture only a tiny fraction of the total population. Even though your input data is healthy, the final scored data becomes artificially zero-inflated because the vast majority of your rows fail to qualify for any segment rules and receive a baseline score of exactly 0.
|
|
457
|
+
When the engine sorts the entire population from highest to lowest score, the small group of customers who actually triggered rules get pushed into Deciles 1 and 2. Because the remaining 80%+ of the population all have a score of 0, Decile 3 onwards fills up entirely with these unsegmented, lowest-risk customers—collapsing their minimum thresholds to 0.
|
|
458
|
+
This indicates that your segment rules are too strict and lack generalizability. To fix this and distribute your scores more evenly across deciles, you can give the engine more breathing room by applying these adjustments:
|
|
459
|
+
**`Increase max_feature_reuse (e.g., set to 2 or 3)`**: This allows highly predictive features to be reused across different segment combinations instead of being locked out after their first use.
|
|
460
|
+
|
|
461
|
+
**`Increase top_n_vars (e.g., set to 25 or 30)`**: This expands the pool of candidate features the engine can look at in later iterations.
|
|
462
|
+
|
|
463
|
+
**`Relax the param_grid thresholds`**: Lower your minimum min_lift or min_sample_size constraints so that smaller or slightly less concentrated segments can still be captured in later rounds.
|
|
464
|
+
|
|
465
|
+
**`Disable diversity constraints (enable_diversity = False)`**: This allows features within the same business category to pair up, unlocking more valid rule combinations.
|
|
466
|
+
|
|
467
|
+
### 4. My dataset may contain target leaked feature (100% correaltion with Target). Will it be taken as important feature?
|
|
468
|
+
|
|
469
|
+
No. The feature will be dropped by Optbinning during segment creation steps.
|
|
470
|
+
Furthermore, if you are using `BigQueryFeatureSelector` the feature IV will be marked as 0 and not considered.
|