clusteraudiencekit 7.4.1__tar.gz → 7.4.2__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.
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.gitignore +2 -0
- clusteraudiencekit-7.4.2/.graphifyignore +31 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/CHANGELOG.md +5 -0
- clusteraudiencekit-7.4.2/PKG-INFO +282 -0
- clusteraudiencekit-7.4.2/README.md +232 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/TECHNICAL_DEBT.md +3 -3
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/pyproject.toml +1 -1
- clusteraudiencekit-7.4.2/tools/graphify/README.md +63 -0
- clusteraudiencekit-7.4.2/tools/graphify/graphify_adapter.py +242 -0
- clusteraudiencekit-7.4.1/PKG-INFO +0 -329
- clusteraudiencekit-7.4.1/README.md +0 -279
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.env.example +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.gitattributes +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.github/dependabot.yml +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.github/pull_request_template.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.github/workflows/ci.yml +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.github/workflows/tests.yml +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.github/workflows/wheels.yml +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/.pre-commit-config.yaml +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/AUDIT.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/CONTRIBUTING.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/Cargo.lock +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/Cargo.toml +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/LICENSE +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/Makefile +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/SECURITY.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/benches/benchmarks.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/clusteraudiencekit/__init__.py +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/CODE_OF_CONDUCT.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/CONTRIBUTORS.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/ROADMAP_HONEST.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/SECURITY_AUDIT.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/SQL_EXPORT.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/architecture/README.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/ARCHITECTURE.md.fabricated-ecosystem +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/CI_ERRORS.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/CONTRIBUTING.md.claude-dupe +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/PYPI_UPLOAD.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/README.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/ROADMAP.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/SECURITY.md.stale-duplicate +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/WORKFLOW_INTEGRATION.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/api-reference.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/architecture.md.stale +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/comparison.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/error-catalog.json +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/getting-started-simple.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/performance-comparison.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/press-release.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/archive/troubleshooting.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/docs/bench/kmeans_1m_results.md +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/examples/basic_segmentation.py +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/examples/sql_export_example.py +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/examples/streaming_updates.py +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/install.sh +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/rust-toolchain.toml +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/scripts/install-curl.sh +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/scripts/install-from-source.sh +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/scripts/install-pip.ps1 +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/scripts/install-pip.sh +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/scripts/test_dashboards_crossplatform.sh +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/activation.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/activation_orchestrator.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/algorithms.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/b2b_governance.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/b2b_segmentation.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/behavioral.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/churn_prediction.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/clustering.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/clv.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/cohorts.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/dashboard.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/drift_detection.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/governance.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/heuristic_score_estimator.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/k_estimation.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/lifecycle.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/lookalike.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/mod.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/neural_networks.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/pattern_discovery.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/platform_adapters.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/plugins.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/price_intelligence.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/privacy.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/profiling.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/quality_metrics.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/revenue_intelligence.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/rfm.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/segment_intelligence.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/segments.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/sql_export.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/streaming.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/engine/temporal_analytics.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/lib.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/python.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/utils/conversions.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/utils/mod.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/src/utils/validation.rs +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/tests/test_basic.py +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/tests/test_clustering.py +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/tests/test_performance.py +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/tests/test_sql_export.py +0 -0
- {clusteraudiencekit-7.4.1 → clusteraudiencekit-7.4.2}/tests/test_wired_modules.py +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Graphify ignore file - https://docs.graphify.com/reference/configuration
|
|
2
|
+
# Keep the scan (and therefore the agent's graph) focused on real source.
|
|
3
|
+
.git/
|
|
4
|
+
.github/
|
|
5
|
+
graphify-out/
|
|
6
|
+
|
|
7
|
+
# Build output / artifacts
|
|
8
|
+
target/
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
node_modules/
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# Caches
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.pyc
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.mypy_cache/
|
|
22
|
+
.ruff_cache/
|
|
23
|
+
.tox/
|
|
24
|
+
.nox/
|
|
25
|
+
.coverage
|
|
26
|
+
htmlcov/
|
|
27
|
+
|
|
28
|
+
# Vendored / generated
|
|
29
|
+
*.min.js
|
|
30
|
+
*.min.css
|
|
31
|
+
*.lock
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clusteraudiencekit
|
|
3
|
+
Version: 7.4.2
|
|
4
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
7
|
+
Classifier: Natural Language :: English
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Office/Business :: News/Diary
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: System :: Monitoring
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Requires-Dist: pandas>=2.0,<3
|
|
22
|
+
Requires-Dist: numpy>=1.24,<2.3
|
|
23
|
+
Requires-Dist: pyarrow>=10.0
|
|
24
|
+
Requires-Dist: pytest>=7.0 ; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-benchmark>=4.0 ; extra == 'dev'
|
|
26
|
+
Requires-Dist: black>=22.0 ; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.1.0 ; extra == 'dev'
|
|
28
|
+
Requires-Dist: mypy>=1.0 ; extra == 'dev'
|
|
29
|
+
Requires-Dist: scikit-learn>=1.0 ; extra == 'dev'
|
|
30
|
+
Requires-Dist: sphinx>=5.0 ; extra == 'docs'
|
|
31
|
+
Requires-Dist: sphinx-rtd-theme>=1.0 ; extra == 'docs'
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Provides-Extra: docs
|
|
34
|
+
License-File: LICENSE
|
|
35
|
+
Summary: Rust-powered customer segmentation: RFM analysis, KMeans/K-Prototypes clustering, churn prediction, customer lifetime value, real-time streaming segmentation, drift detection, lookalike audiences, cohort analytics, lifecycle tracking, and differential privacy / k-anonymity.
|
|
36
|
+
Keywords: clustering,customer-segmentation,rfm-analysis,martech,audience-segmentation,customer-analytics,machine-learning,k-means,k-prototypes,differential-privacy,k-anonymity,segmentation-engine,crm,customer-lifetime-value,churn-prediction,cohort-analysis,audience-targeting,marketing-automation,email-marketing,retargeting,customer-scoring,behavioral-analytics,data-science,python-library,real-time-processing,streaming-data,marketing-tech,audience-modeling,rust-performance,predictive-analytics
|
|
37
|
+
Author-email: Georgi Mammen Mullassery <mullassery@gmail.com>
|
|
38
|
+
Maintainer-email: Georgi Mammen Mullassery <mullassery@gmail.com>
|
|
39
|
+
License-Expression: Apache-2.0
|
|
40
|
+
Requires-Python: >=3.8
|
|
41
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
42
|
+
Project-URL: Bug Tracker, https://github.com/Mullassery/ClusterAudienceKit/issues
|
|
43
|
+
Project-URL: Changelog, https://github.com/Mullassery/ClusterAudienceKit/releases
|
|
44
|
+
Project-URL: Discussions, https://github.com/Mullassery/ClusterAudienceKit/discussions
|
|
45
|
+
Project-URL: Documentation, https://github.com/Mullassery/ClusterAudienceKit#readme
|
|
46
|
+
Project-URL: Homepage, https://github.com/Mullassery/ClusterAudienceKit
|
|
47
|
+
Project-URL: Repository, https://github.com/Mullassery/ClusterAudienceKit
|
|
48
|
+
Project-URL: Source Code, https://github.com/Mullassery/ClusterAudienceKit/tree/main
|
|
49
|
+
|
|
50
|
+
# ClusterAudienceKit
|
|
51
|
+
|
|
52
|
+
**Rust-powered customer segmentation with a Python API: RFM analysis, clustering, churn scoring, CLV, and privacy-aware audience tooling in one dependency.**
|
|
53
|
+
|
|
54
|
+
[](LICENSE)
|
|
55
|
+
[](https://pypi.org/project/clusteraudiencekit/)
|
|
56
|
+
[](https://www.python.org)
|
|
57
|
+
[](https://github.com/Mullassery/ClusterAudienceKit/actions)
|
|
58
|
+
[](https://github.com/Graphify-Labs/graphify)
|
|
59
|
+
|
|
60
|
+
## What it is
|
|
61
|
+
|
|
62
|
+
ClusterAudienceKit is a Rust-powered customer segmentation engine with Python bindings.
|
|
63
|
+
It covers RFM analysis, KMeans/K-Prototypes clustering, cluster-quality metrics, automatic
|
|
64
|
+
K selection, churn prediction, customer lifetime value, SQL export to 8 warehouse dialects,
|
|
65
|
+
differential privacy / k-anonymity, real-time streaming segmentation, drift detection,
|
|
66
|
+
lookalike audiences, cohort analytics, lifecycle tracking, rule-based behavioral
|
|
67
|
+
segmentation, and segment profiling — all real, tested Rust logic exposed through the
|
|
68
|
+
compiled Python extension (`import clusteraudiencekit`).
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
| Capability | Python entry points |
|
|
73
|
+
|---|---|
|
|
74
|
+
| RFM analysis | `calculate_rfm`, `RFMConfig`, `RFMScore` |
|
|
75
|
+
| KMeans / K-Prototypes clustering | `kmeans`, `AudienceSegmenter` |
|
|
76
|
+
| Cluster quality metrics | `silhouette_score`, `davies_bouldin_score`, `calinski_harabasz_score`, `assess_cluster_quality` |
|
|
77
|
+
| Automatic K selection | `estimate_k_elbow`, `estimate_k_gap_statistic`, `estimate_k_silhouette`, `estimate_k_combined` |
|
|
78
|
+
| Churn prediction (incl. real AUC-ROC) | `ChurnPrediction`, `ChurnRiskLevel` |
|
|
79
|
+
| Customer lifetime value | `CustomerLTV`, `calculate_simple_ltv` |
|
|
80
|
+
| SQL export (8 dialects, injection-safe) | `export_segment_sql`, `export_all_segments_sql`, `get_supported_sql_dialects` |
|
|
81
|
+
| Differential privacy & k-anonymity | `PyPrivacyBudget`, `add_laplace_noise`, `add_gaussian_noise`, `check_k_anonymity`, `suppress_to_k_anonymous`, `generalize_numeric` |
|
|
82
|
+
| Real-time streaming segmentation | `PyStreamingSegmentationEngine`, `PyStreamingEvent`, `PyStreamingConfig` |
|
|
83
|
+
| Drift detection | `kolmogorov_smirnov`, `hellinger_distance`, `chi_square_drift`, `detect_feature_drift`, `detect_segment_composition_change` |
|
|
84
|
+
| Lookalike audiences | `generate_lookalike`, `find_similar_customers`, `cosine_similarity` |
|
|
85
|
+
| Cohort analytics | `create_cohort`, `cohort_id_for`, `compare_cohorts`, `aggregate_cohorts_by_period`, `cohort_retention_table` |
|
|
86
|
+
| Lifecycle tracking | `classify_lifecycle_stage`, `lifecycle_retention_actions`, `lifecycle_stage_distribution` |
|
|
87
|
+
| Rule-based behavioral segmentation | `PyBehavioralSegmenter`, `PyBehavioralSegment`, `PyBehavioralRule`, `PyCondition` |
|
|
88
|
+
| Segment profiling | `profile_segment` |
|
|
89
|
+
|
|
90
|
+
Segmentation output is 13 named RFM segments (Champions, Loyal Customers, Potential
|
|
91
|
+
Loyalists, At Risk, Cannot Lose Them, About to Sleep, New Customers, Promising, Need
|
|
92
|
+
Attention, Lost, At Risk - Sleeping, Hibernating, VIP).
|
|
93
|
+
|
|
94
|
+
## Who it's for
|
|
95
|
+
|
|
96
|
+
- **Marketing and data teams** building a segmentation pipeline on a large transaction
|
|
97
|
+
table where scikit-learn's Python-level clustering is the bottleneck — the Rust core is
|
|
98
|
+
rayon-parallelized and deterministic for a given seed.
|
|
99
|
+
- **Teams exporting customer segments directly into a warehouse** — `export_segment_sql`
|
|
100
|
+
generates injection-safe SQL for 8 dialects rather than hand-writing per-warehouse
|
|
101
|
+
export scripts.
|
|
102
|
+
- **Privacy-constrained segmentation** — differential privacy (Laplace/Gaussian noise) and
|
|
103
|
+
k-anonymity suppression/generalization are real, tested primitives, not a compliance
|
|
104
|
+
checkbox.
|
|
105
|
+
|
|
106
|
+
## What it is not
|
|
107
|
+
|
|
108
|
+
- **Not external platform activation.** Pushing segments to ad/CRM platforms, B2B
|
|
109
|
+
governance/workflow tooling, a dashboard UI, and a plugin framework are deliberately out
|
|
110
|
+
of scope for this library.
|
|
111
|
+
- **Not a scikit-learn wrapper.** The algorithms are real, independently unit-tested Rust
|
|
112
|
+
implementations, not thin bindings over Python libraries.
|
|
113
|
+
- **Not feature-scaling-aware by default.** `AudienceSegmenter` does no internal
|
|
114
|
+
standardization; on real data you should standardize recency/frequency/monetary yourself
|
|
115
|
+
before calling `.fit()` (see [Known issues](#known-issues)).
|
|
116
|
+
- **K-Prototypes categorical support is partial.** `AudienceSegmenter.fit()` accepts only a
|
|
117
|
+
numeric feature matrix today, so selecting K-Prototypes through that class runs
|
|
118
|
+
numeric-only (effectively KMeans). The underlying Rust implementation does support mixed
|
|
119
|
+
data; it just isn't reachable from that Python entry point yet.
|
|
120
|
+
- **Six Rust modules are real but not yet exposed to Python:** `segment_intelligence`,
|
|
121
|
+
`pattern_discovery`, `temporal_analytics`, `price_intelligence`, `revenue_intelligence`,
|
|
122
|
+
and `neural_networks`. They're tested, not stubs; wiring them to the Python API is a
|
|
123
|
+
follow-up release.
|
|
124
|
+
|
|
125
|
+
## Project status
|
|
126
|
+
|
|
127
|
+
**Production/Stable** per the package classifier (version 7.4.1), with the honest gaps
|
|
128
|
+
above. This project tracks its own implementation-vs.-plan status on purpose; see
|
|
129
|
+
[`docs/ROADMAP_HONEST.md`](docs/ROADMAP_HONEST.md). Changes are tracked in
|
|
130
|
+
[CHANGELOG.md](CHANGELOG.md).
|
|
131
|
+
|
|
132
|
+
## Installation
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
pip install clusteraudiencekit
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Requires Python 3.8+, with NumPy, Pandas, and PyArrow (see `pyproject.toml` for exact
|
|
139
|
+
ranges). The compiled Rust core ships as a platform wheel, so no local Rust toolchain is
|
|
140
|
+
needed — **but** the only wheel currently published to PyPI is macOS ARM64 (`cp39-abi3`),
|
|
141
|
+
alongside an sdist. On any other platform, `pip install` falls back to building the sdist
|
|
142
|
+
from source, which does require a Rust toolchain; or clone the repo and build locally with
|
|
143
|
+
[`maturin`](https://github.com/PyO3/maturin) (`pip install maturin && maturin develop
|
|
144
|
+
--release`).
|
|
145
|
+
|
|
146
|
+
## Quick start
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from clusteraudiencekit import AudienceSegmenter, RFMConfig, calculate_rfm
|
|
150
|
+
|
|
151
|
+
# transactions: list of (customer_id, iso8601_date, amount).
|
|
152
|
+
# n_clusters must be <= the number of distinct customers — use your real,
|
|
153
|
+
# larger transaction history here; this toy example has 3 customers.
|
|
154
|
+
transactions = [
|
|
155
|
+
("cust_1", "2026-06-01T00:00:00+00:00", 120.0),
|
|
156
|
+
("cust_1", "2026-07-15T00:00:00+00:00", 80.0),
|
|
157
|
+
("cust_2", "2026-01-10T00:00:00+00:00", 15.0),
|
|
158
|
+
("cust_3", "2026-08-01T00:00:00+00:00", 500.0),
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
# Real RFM scoring (recency/frequency/monetary, quintile-scored, 13-segment
|
|
162
|
+
# classification), not a mock.
|
|
163
|
+
scores = calculate_rfm(transactions, RFMConfig())
|
|
164
|
+
|
|
165
|
+
# Cluster customers by their RFM features with real KMeans (k-means++ init,
|
|
166
|
+
# rayon-parallelized assignment step, deterministic for a given seed).
|
|
167
|
+
features = [[s.recency, s.frequency, s.monetary] for s in scores]
|
|
168
|
+
segmenter = AudienceSegmenter(2)
|
|
169
|
+
segmenter.fit(features)
|
|
170
|
+
segments = segmenter.predict(features)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Usage
|
|
174
|
+
|
|
175
|
+
### Why ClusterAudienceKit?
|
|
176
|
+
|
|
177
|
+
Marketing/data teams need RFM segmentation, clustering, churn scoring, and CLV estimation,
|
|
178
|
+
usually stitched together from several tools. This package does the core numeric work in
|
|
179
|
+
Rust (fast, deterministic, real unit-tested algorithms — not scikit-learn wrappers) with a
|
|
180
|
+
Python API, so you get one dependency instead of five, and you can inspect exactly what's
|
|
181
|
+
real (see [`docs/ROADMAP_HONEST.md`](docs/ROADMAP_HONEST.md)).
|
|
182
|
+
|
|
183
|
+
### vs scikit-learn & lifetimes
|
|
184
|
+
|
|
185
|
+
No single OSS package covers everything here, so this compares the two pieces with direct
|
|
186
|
+
real competitors: clustering vs `scikit-learn`'s KMeans, and CLV vs the `lifetimes`
|
|
187
|
+
package's real BG/NBD probabilistic model. Tested against a real public e-commerce
|
|
188
|
+
dataset — the UCI "Online Retail" transaction log (541,909 real transactions, cleaned to
|
|
189
|
+
397,884 real rows / 4,338 real customers with valid quantity/price/customer ID) — not
|
|
190
|
+
synthetic data.
|
|
191
|
+
|
|
192
|
+
| | ClusterAudienceKit | scikit-learn |
|
|
193
|
+
|---|---|---|
|
|
194
|
+
| RFM computation (4,338 real customers) | 0.026s | — (not scikit-learn's job) |
|
|
195
|
+
| KMeans, K=5, on raw RFM features | 0.001s, silhouette=0.9502 | 0.025s (unscaled, matching CAK's real input), silhouette=0.8387, `RuntimeWarning: overflow encountered in matmul` |
|
|
196
|
+
| KMeans, K=5, standardized features | — (no built-in scaling) | 0.080s, silhouette=0.7744 |
|
|
197
|
+
|
|
198
|
+
**The silhouette numbers above are misleading on their own, and this is the real,
|
|
199
|
+
important finding, not the timing.** Inspecting the actual cluster sizes on real,
|
|
200
|
+
unscaled RFM features: **4,300 of 4,338 real customers (99.1%) land in one giant
|
|
201
|
+
cluster**, with 4 tiny outlier clusters splitting off customers with extreme real monetary
|
|
202
|
+
values (one real customer spent $280,206 vs. a $2,054 mean). That's a textbook
|
|
203
|
+
unscaled-KMeans failure — `monetary` has ~450x the numeric range of
|
|
204
|
+
`recency`/`frequency`, so raw Euclidean distance is dominated by it, and the "high"
|
|
205
|
+
silhouette score is an artifact of that degenerate split, not good segmentation.
|
|
206
|
+
Standardize recency/frequency/monetary yourself (e.g.
|
|
207
|
+
`sklearn.preprocessing.StandardScaler`) before calling `.fit()` on real data.
|
|
208
|
+
|
|
209
|
+
| | ClusterAudienceKit `calculate_simple_ltv` | `lifetimes` (BG/NBD + Gamma-Gamma) |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| Method | Deterministic: `(total_spent / days_active) * 365 * lifespan_years` | Real probabilistic model fit on repeat-purchase patterns |
|
|
212
|
+
| Repeat-purchaser customers scored by both | 2,790 real customers | 2,790 real customers |
|
|
213
|
+
| Rank correlation (Spearman ρ) between the two tools' CLV rankings | **0.7111** (p < 1e-300) | — |
|
|
214
|
+
|
|
215
|
+
A substantial, real positive correlation — the two independently-computed approaches
|
|
216
|
+
broadly agree on who a business's most valuable real customers are.
|
|
217
|
+
|
|
218
|
+
## Documentation
|
|
219
|
+
|
|
220
|
+
- [Honest roadmap](docs/ROADMAP_HONEST.md) — what's real, what's deferred, and why.
|
|
221
|
+
- [Architecture](docs/architecture/README.md) — real module layout and data flow, checked
|
|
222
|
+
against `src/`.
|
|
223
|
+
- [Security audit](docs/SECURITY_AUDIT.md)
|
|
224
|
+
- [SQL export reference](docs/SQL_EXPORT.md)
|
|
225
|
+
- [Examples](examples/)
|
|
226
|
+
|
|
227
|
+
## Known issues
|
|
228
|
+
|
|
229
|
+
Verified as of the last audit (October 2026):
|
|
230
|
+
|
|
231
|
+
- **The only wheel on PyPI is macOS ARM64 (`cp39-abi3`), plus an sdist.** A multi-platform
|
|
232
|
+
wheel-building CI workflow (`.github/workflows/wheels.yml`) builds and tests wheels on
|
|
233
|
+
Linux, macOS (arm64 + x86_64), and Windows, and is wired to publish via Trusted
|
|
234
|
+
Publishing on tagged releases; the PyPI-side Trusted Publisher still has to be configured
|
|
235
|
+
before that job can succeed.
|
|
236
|
+
- **No internal feature standardization.** `AudienceSegmenter` does not standardize inputs,
|
|
237
|
+
and neither the quick-start example nor `assess_cluster_quality` warns about the
|
|
238
|
+
unscaled-KMeans failure described above. Standardize your features first on real data.
|
|
239
|
+
- **K-Prototypes categorical support is partial** (numeric-only through
|
|
240
|
+
`AudienceSegmenter.fit()`; see above).
|
|
241
|
+
- **`v7.0.0` remains installable from PyPI despite a confirmed import-crashing bug.** If you
|
|
242
|
+
have it pinned, upgrade to `>=7.2.0`.
|
|
243
|
+
- **`cargo audit`: 1 open advisory with no fix available.** `anyhow` 1.0.102 has an
|
|
244
|
+
unsoundness advisory in `Error::downcast_mut()`
|
|
245
|
+
([RUSTSEC-2026-0190](https://rustsec.org/advisories/RUSTSEC-2026-0190)); tracked in
|
|
246
|
+
[RepoIssues #34](https://github.com/Mullassery/RepoIssues/issues/34).
|
|
247
|
+
- **Two Rust utility functions are unimplemented stubs.** `pandas_to_arrow`/`arrow_to_pandas`
|
|
248
|
+
in `src/utils/conversions.rs` return `Err("Not implemented")`; they aren't called elsewhere
|
|
249
|
+
or exposed to Python.
|
|
250
|
+
- **Six tested Rust modules are implemented but not yet wired to the Python API** (see
|
|
251
|
+
"What it is not").
|
|
252
|
+
|
|
253
|
+
## Contributing
|
|
254
|
+
|
|
255
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Development quickstart:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
maturin develop --release # build the Rust extension + install editable
|
|
259
|
+
cargo test --no-default-features # Rust unit tests
|
|
260
|
+
pytest tests/ -v # Python tests
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Note the `--no-default-features` flag: the default `extension-module` feature omits linking
|
|
264
|
+
against libpython, which a standalone `cargo test` binary needs. See `CONTRIBUTING.md` and
|
|
265
|
+
[`docs/ROADMAP_HONEST.md`](docs/ROADMAP_HONEST.md) for details.
|
|
266
|
+
|
|
267
|
+
## Related projects
|
|
268
|
+
|
|
269
|
+
Other tools from the same family, for adjacent parts of the customer/data stack:
|
|
270
|
+
|
|
271
|
+
- [PyReverseETL](https://github.com/Mullassery/PyReverseETL) — reverse ETL runtime: move data into CRMs and marketing tools with lineage and compliance enforcement.
|
|
272
|
+
- [PySynthData](https://github.com/Mullassery/PySynthData) — synthetic data generation for ML training: realistic datasets for model development and testing.
|
|
273
|
+
- [StatGuardian](https://github.com/Mullassery/StatGuardian) — fast, declarative data quality framework (Rust): schema validation, drift detection, anomaly detection.
|
|
274
|
+
- [PyWeatherEnriched](https://github.com/Mullassery/PyWeatherEnriched) — real historical weather and geocoding enrichment for ML pipelines.
|
|
275
|
+
- [PyDBTGuard](https://github.com/Mullassery/PyDBTGuard) — analyzes a dbt project's `manifest.json` to flag risky tests, map blast radius, and estimate test cost.
|
|
276
|
+
|
|
277
|
+
[Browse all projects →](https://github.com/Mullassery?tab=repositories)
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
Apache License 2.0. See [`LICENSE`](LICENSE) for the full terms.
|
|
282
|
+
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# ClusterAudienceKit
|
|
2
|
+
|
|
3
|
+
**Rust-powered customer segmentation with a Python API: RFM analysis, clustering, churn scoring, CLV, and privacy-aware audience tooling in one dependency.**
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://pypi.org/project/clusteraudiencekit/)
|
|
7
|
+
[](https://www.python.org)
|
|
8
|
+
[](https://github.com/Mullassery/ClusterAudienceKit/actions)
|
|
9
|
+
[](https://github.com/Graphify-Labs/graphify)
|
|
10
|
+
|
|
11
|
+
## What it is
|
|
12
|
+
|
|
13
|
+
ClusterAudienceKit is a Rust-powered customer segmentation engine with Python bindings.
|
|
14
|
+
It covers RFM analysis, KMeans/K-Prototypes clustering, cluster-quality metrics, automatic
|
|
15
|
+
K selection, churn prediction, customer lifetime value, SQL export to 8 warehouse dialects,
|
|
16
|
+
differential privacy / k-anonymity, real-time streaming segmentation, drift detection,
|
|
17
|
+
lookalike audiences, cohort analytics, lifecycle tracking, rule-based behavioral
|
|
18
|
+
segmentation, and segment profiling — all real, tested Rust logic exposed through the
|
|
19
|
+
compiled Python extension (`import clusteraudiencekit`).
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
| Capability | Python entry points |
|
|
24
|
+
|---|---|
|
|
25
|
+
| RFM analysis | `calculate_rfm`, `RFMConfig`, `RFMScore` |
|
|
26
|
+
| KMeans / K-Prototypes clustering | `kmeans`, `AudienceSegmenter` |
|
|
27
|
+
| Cluster quality metrics | `silhouette_score`, `davies_bouldin_score`, `calinski_harabasz_score`, `assess_cluster_quality` |
|
|
28
|
+
| Automatic K selection | `estimate_k_elbow`, `estimate_k_gap_statistic`, `estimate_k_silhouette`, `estimate_k_combined` |
|
|
29
|
+
| Churn prediction (incl. real AUC-ROC) | `ChurnPrediction`, `ChurnRiskLevel` |
|
|
30
|
+
| Customer lifetime value | `CustomerLTV`, `calculate_simple_ltv` |
|
|
31
|
+
| SQL export (8 dialects, injection-safe) | `export_segment_sql`, `export_all_segments_sql`, `get_supported_sql_dialects` |
|
|
32
|
+
| Differential privacy & k-anonymity | `PyPrivacyBudget`, `add_laplace_noise`, `add_gaussian_noise`, `check_k_anonymity`, `suppress_to_k_anonymous`, `generalize_numeric` |
|
|
33
|
+
| Real-time streaming segmentation | `PyStreamingSegmentationEngine`, `PyStreamingEvent`, `PyStreamingConfig` |
|
|
34
|
+
| Drift detection | `kolmogorov_smirnov`, `hellinger_distance`, `chi_square_drift`, `detect_feature_drift`, `detect_segment_composition_change` |
|
|
35
|
+
| Lookalike audiences | `generate_lookalike`, `find_similar_customers`, `cosine_similarity` |
|
|
36
|
+
| Cohort analytics | `create_cohort`, `cohort_id_for`, `compare_cohorts`, `aggregate_cohorts_by_period`, `cohort_retention_table` |
|
|
37
|
+
| Lifecycle tracking | `classify_lifecycle_stage`, `lifecycle_retention_actions`, `lifecycle_stage_distribution` |
|
|
38
|
+
| Rule-based behavioral segmentation | `PyBehavioralSegmenter`, `PyBehavioralSegment`, `PyBehavioralRule`, `PyCondition` |
|
|
39
|
+
| Segment profiling | `profile_segment` |
|
|
40
|
+
|
|
41
|
+
Segmentation output is 13 named RFM segments (Champions, Loyal Customers, Potential
|
|
42
|
+
Loyalists, At Risk, Cannot Lose Them, About to Sleep, New Customers, Promising, Need
|
|
43
|
+
Attention, Lost, At Risk - Sleeping, Hibernating, VIP).
|
|
44
|
+
|
|
45
|
+
## Who it's for
|
|
46
|
+
|
|
47
|
+
- **Marketing and data teams** building a segmentation pipeline on a large transaction
|
|
48
|
+
table where scikit-learn's Python-level clustering is the bottleneck — the Rust core is
|
|
49
|
+
rayon-parallelized and deterministic for a given seed.
|
|
50
|
+
- **Teams exporting customer segments directly into a warehouse** — `export_segment_sql`
|
|
51
|
+
generates injection-safe SQL for 8 dialects rather than hand-writing per-warehouse
|
|
52
|
+
export scripts.
|
|
53
|
+
- **Privacy-constrained segmentation** — differential privacy (Laplace/Gaussian noise) and
|
|
54
|
+
k-anonymity suppression/generalization are real, tested primitives, not a compliance
|
|
55
|
+
checkbox.
|
|
56
|
+
|
|
57
|
+
## What it is not
|
|
58
|
+
|
|
59
|
+
- **Not external platform activation.** Pushing segments to ad/CRM platforms, B2B
|
|
60
|
+
governance/workflow tooling, a dashboard UI, and a plugin framework are deliberately out
|
|
61
|
+
of scope for this library.
|
|
62
|
+
- **Not a scikit-learn wrapper.** The algorithms are real, independently unit-tested Rust
|
|
63
|
+
implementations, not thin bindings over Python libraries.
|
|
64
|
+
- **Not feature-scaling-aware by default.** `AudienceSegmenter` does no internal
|
|
65
|
+
standardization; on real data you should standardize recency/frequency/monetary yourself
|
|
66
|
+
before calling `.fit()` (see [Known issues](#known-issues)).
|
|
67
|
+
- **K-Prototypes categorical support is partial.** `AudienceSegmenter.fit()` accepts only a
|
|
68
|
+
numeric feature matrix today, so selecting K-Prototypes through that class runs
|
|
69
|
+
numeric-only (effectively KMeans). The underlying Rust implementation does support mixed
|
|
70
|
+
data; it just isn't reachable from that Python entry point yet.
|
|
71
|
+
- **Six Rust modules are real but not yet exposed to Python:** `segment_intelligence`,
|
|
72
|
+
`pattern_discovery`, `temporal_analytics`, `price_intelligence`, `revenue_intelligence`,
|
|
73
|
+
and `neural_networks`. They're tested, not stubs; wiring them to the Python API is a
|
|
74
|
+
follow-up release.
|
|
75
|
+
|
|
76
|
+
## Project status
|
|
77
|
+
|
|
78
|
+
**Production/Stable** per the package classifier (version 7.4.1), with the honest gaps
|
|
79
|
+
above. This project tracks its own implementation-vs.-plan status on purpose; see
|
|
80
|
+
[`docs/ROADMAP_HONEST.md`](docs/ROADMAP_HONEST.md). Changes are tracked in
|
|
81
|
+
[CHANGELOG.md](CHANGELOG.md).
|
|
82
|
+
|
|
83
|
+
## Installation
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pip install clusteraudiencekit
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Requires Python 3.8+, with NumPy, Pandas, and PyArrow (see `pyproject.toml` for exact
|
|
90
|
+
ranges). The compiled Rust core ships as a platform wheel, so no local Rust toolchain is
|
|
91
|
+
needed — **but** the only wheel currently published to PyPI is macOS ARM64 (`cp39-abi3`),
|
|
92
|
+
alongside an sdist. On any other platform, `pip install` falls back to building the sdist
|
|
93
|
+
from source, which does require a Rust toolchain; or clone the repo and build locally with
|
|
94
|
+
[`maturin`](https://github.com/PyO3/maturin) (`pip install maturin && maturin develop
|
|
95
|
+
--release`).
|
|
96
|
+
|
|
97
|
+
## Quick start
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from clusteraudiencekit import AudienceSegmenter, RFMConfig, calculate_rfm
|
|
101
|
+
|
|
102
|
+
# transactions: list of (customer_id, iso8601_date, amount).
|
|
103
|
+
# n_clusters must be <= the number of distinct customers — use your real,
|
|
104
|
+
# larger transaction history here; this toy example has 3 customers.
|
|
105
|
+
transactions = [
|
|
106
|
+
("cust_1", "2026-06-01T00:00:00+00:00", 120.0),
|
|
107
|
+
("cust_1", "2026-07-15T00:00:00+00:00", 80.0),
|
|
108
|
+
("cust_2", "2026-01-10T00:00:00+00:00", 15.0),
|
|
109
|
+
("cust_3", "2026-08-01T00:00:00+00:00", 500.0),
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
# Real RFM scoring (recency/frequency/monetary, quintile-scored, 13-segment
|
|
113
|
+
# classification), not a mock.
|
|
114
|
+
scores = calculate_rfm(transactions, RFMConfig())
|
|
115
|
+
|
|
116
|
+
# Cluster customers by their RFM features with real KMeans (k-means++ init,
|
|
117
|
+
# rayon-parallelized assignment step, deterministic for a given seed).
|
|
118
|
+
features = [[s.recency, s.frequency, s.monetary] for s in scores]
|
|
119
|
+
segmenter = AudienceSegmenter(2)
|
|
120
|
+
segmenter.fit(features)
|
|
121
|
+
segments = segmenter.predict(features)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Usage
|
|
125
|
+
|
|
126
|
+
### Why ClusterAudienceKit?
|
|
127
|
+
|
|
128
|
+
Marketing/data teams need RFM segmentation, clustering, churn scoring, and CLV estimation,
|
|
129
|
+
usually stitched together from several tools. This package does the core numeric work in
|
|
130
|
+
Rust (fast, deterministic, real unit-tested algorithms — not scikit-learn wrappers) with a
|
|
131
|
+
Python API, so you get one dependency instead of five, and you can inspect exactly what's
|
|
132
|
+
real (see [`docs/ROADMAP_HONEST.md`](docs/ROADMAP_HONEST.md)).
|
|
133
|
+
|
|
134
|
+
### vs scikit-learn & lifetimes
|
|
135
|
+
|
|
136
|
+
No single OSS package covers everything here, so this compares the two pieces with direct
|
|
137
|
+
real competitors: clustering vs `scikit-learn`'s KMeans, and CLV vs the `lifetimes`
|
|
138
|
+
package's real BG/NBD probabilistic model. Tested against a real public e-commerce
|
|
139
|
+
dataset — the UCI "Online Retail" transaction log (541,909 real transactions, cleaned to
|
|
140
|
+
397,884 real rows / 4,338 real customers with valid quantity/price/customer ID) — not
|
|
141
|
+
synthetic data.
|
|
142
|
+
|
|
143
|
+
| | ClusterAudienceKit | scikit-learn |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| RFM computation (4,338 real customers) | 0.026s | — (not scikit-learn's job) |
|
|
146
|
+
| KMeans, K=5, on raw RFM features | 0.001s, silhouette=0.9502 | 0.025s (unscaled, matching CAK's real input), silhouette=0.8387, `RuntimeWarning: overflow encountered in matmul` |
|
|
147
|
+
| KMeans, K=5, standardized features | — (no built-in scaling) | 0.080s, silhouette=0.7744 |
|
|
148
|
+
|
|
149
|
+
**The silhouette numbers above are misleading on their own, and this is the real,
|
|
150
|
+
important finding, not the timing.** Inspecting the actual cluster sizes on real,
|
|
151
|
+
unscaled RFM features: **4,300 of 4,338 real customers (99.1%) land in one giant
|
|
152
|
+
cluster**, with 4 tiny outlier clusters splitting off customers with extreme real monetary
|
|
153
|
+
values (one real customer spent $280,206 vs. a $2,054 mean). That's a textbook
|
|
154
|
+
unscaled-KMeans failure — `monetary` has ~450x the numeric range of
|
|
155
|
+
`recency`/`frequency`, so raw Euclidean distance is dominated by it, and the "high"
|
|
156
|
+
silhouette score is an artifact of that degenerate split, not good segmentation.
|
|
157
|
+
Standardize recency/frequency/monetary yourself (e.g.
|
|
158
|
+
`sklearn.preprocessing.StandardScaler`) before calling `.fit()` on real data.
|
|
159
|
+
|
|
160
|
+
| | ClusterAudienceKit `calculate_simple_ltv` | `lifetimes` (BG/NBD + Gamma-Gamma) |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| Method | Deterministic: `(total_spent / days_active) * 365 * lifespan_years` | Real probabilistic model fit on repeat-purchase patterns |
|
|
163
|
+
| Repeat-purchaser customers scored by both | 2,790 real customers | 2,790 real customers |
|
|
164
|
+
| Rank correlation (Spearman ρ) between the two tools' CLV rankings | **0.7111** (p < 1e-300) | — |
|
|
165
|
+
|
|
166
|
+
A substantial, real positive correlation — the two independently-computed approaches
|
|
167
|
+
broadly agree on who a business's most valuable real customers are.
|
|
168
|
+
|
|
169
|
+
## Documentation
|
|
170
|
+
|
|
171
|
+
- [Honest roadmap](docs/ROADMAP_HONEST.md) — what's real, what's deferred, and why.
|
|
172
|
+
- [Architecture](docs/architecture/README.md) — real module layout and data flow, checked
|
|
173
|
+
against `src/`.
|
|
174
|
+
- [Security audit](docs/SECURITY_AUDIT.md)
|
|
175
|
+
- [SQL export reference](docs/SQL_EXPORT.md)
|
|
176
|
+
- [Examples](examples/)
|
|
177
|
+
|
|
178
|
+
## Known issues
|
|
179
|
+
|
|
180
|
+
Verified as of the last audit (October 2026):
|
|
181
|
+
|
|
182
|
+
- **The only wheel on PyPI is macOS ARM64 (`cp39-abi3`), plus an sdist.** A multi-platform
|
|
183
|
+
wheel-building CI workflow (`.github/workflows/wheels.yml`) builds and tests wheels on
|
|
184
|
+
Linux, macOS (arm64 + x86_64), and Windows, and is wired to publish via Trusted
|
|
185
|
+
Publishing on tagged releases; the PyPI-side Trusted Publisher still has to be configured
|
|
186
|
+
before that job can succeed.
|
|
187
|
+
- **No internal feature standardization.** `AudienceSegmenter` does not standardize inputs,
|
|
188
|
+
and neither the quick-start example nor `assess_cluster_quality` warns about the
|
|
189
|
+
unscaled-KMeans failure described above. Standardize your features first on real data.
|
|
190
|
+
- **K-Prototypes categorical support is partial** (numeric-only through
|
|
191
|
+
`AudienceSegmenter.fit()`; see above).
|
|
192
|
+
- **`v7.0.0` remains installable from PyPI despite a confirmed import-crashing bug.** If you
|
|
193
|
+
have it pinned, upgrade to `>=7.2.0`.
|
|
194
|
+
- **`cargo audit`: 1 open advisory with no fix available.** `anyhow` 1.0.102 has an
|
|
195
|
+
unsoundness advisory in `Error::downcast_mut()`
|
|
196
|
+
([RUSTSEC-2026-0190](https://rustsec.org/advisories/RUSTSEC-2026-0190)); tracked in
|
|
197
|
+
[RepoIssues #34](https://github.com/Mullassery/RepoIssues/issues/34).
|
|
198
|
+
- **Two Rust utility functions are unimplemented stubs.** `pandas_to_arrow`/`arrow_to_pandas`
|
|
199
|
+
in `src/utils/conversions.rs` return `Err("Not implemented")`; they aren't called elsewhere
|
|
200
|
+
or exposed to Python.
|
|
201
|
+
- **Six tested Rust modules are implemented but not yet wired to the Python API** (see
|
|
202
|
+
"What it is not").
|
|
203
|
+
|
|
204
|
+
## Contributing
|
|
205
|
+
|
|
206
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Development quickstart:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
maturin develop --release # build the Rust extension + install editable
|
|
210
|
+
cargo test --no-default-features # Rust unit tests
|
|
211
|
+
pytest tests/ -v # Python tests
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Note the `--no-default-features` flag: the default `extension-module` feature omits linking
|
|
215
|
+
against libpython, which a standalone `cargo test` binary needs. See `CONTRIBUTING.md` and
|
|
216
|
+
[`docs/ROADMAP_HONEST.md`](docs/ROADMAP_HONEST.md) for details.
|
|
217
|
+
|
|
218
|
+
## Related projects
|
|
219
|
+
|
|
220
|
+
Other tools from the same family, for adjacent parts of the customer/data stack:
|
|
221
|
+
|
|
222
|
+
- [PyReverseETL](https://github.com/Mullassery/PyReverseETL) — reverse ETL runtime: move data into CRMs and marketing tools with lineage and compliance enforcement.
|
|
223
|
+
- [PySynthData](https://github.com/Mullassery/PySynthData) — synthetic data generation for ML training: realistic datasets for model development and testing.
|
|
224
|
+
- [StatGuardian](https://github.com/Mullassery/StatGuardian) — fast, declarative data quality framework (Rust): schema validation, drift detection, anomaly detection.
|
|
225
|
+
- [PyWeatherEnriched](https://github.com/Mullassery/PyWeatherEnriched) — real historical weather and geocoding enrichment for ML pipelines.
|
|
226
|
+
- [PyDBTGuard](https://github.com/Mullassery/PyDBTGuard) — analyzes a dbt project's `manifest.json` to flag risky tests, map blast radius, and estimate test cost.
|
|
227
|
+
|
|
228
|
+
[Browse all projects →](https://github.com/Mullassery?tab=repositories)
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
Apache License 2.0. See [`LICENSE`](LICENSE) for the full terms.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Executive Summary
|
|
4
4
|
|
|
5
5
|
Total items: 9
|
|
6
|
-
Open:
|
|
6
|
+
Open: 5 · Resolved (this pass): 6 (overlaps with historical where a fix
|
|
7
7
|
closed more than one angle of the same item — see per-item notes) ·
|
|
8
8
|
Future/Deferred: 2
|
|
9
9
|
Critical: 0 · High: 1 · Medium: 4 · Low: 4
|
|
@@ -43,7 +43,7 @@ None found.
|
|
|
43
43
|
|
|
44
44
|
| ID | Category | Description | Source | Status | Fix |
|
|
45
45
|
|---|---|---|---|---|---|
|
|
46
|
-
| TD-0008 | TEST_DEBT | `tests/test_performance.py` uses `@pytest.mark.benchmark` without registering it, producing a `PytestUnknownMarkWarning` on every run (2 occurrences). | SOURCE_CODE (pytest output) |
|
|
46
|
+
| TD-0008 | TEST_DEBT | `tests/test_performance.py` uses `@pytest.mark.benchmark` without registering it, producing a `PytestUnknownMarkWarning` on every run (2 occurrences). | SOURCE_CODE (pytest output) | **RESOLVED** (already fixed in tree) | The `benchmark` marker is registered in `pyproject.toml`'s `[tool.pytest.ini_options].markers` (line 102), so the `PytestUnknownMarkWarning` no longer occurs — this register was recorded as OPEN by mistake. |
|
|
47
47
|
| TD-0009 | REFACTOR | 30 pre-existing clippy warnings remain, all confirmed (by file) concentrated in modules that are either explicitly deferred (`neural_networks.rs`, `temporal_analytics.rs`, `b2b_governance.rs`, `segment_intelligence.rs`, `pattern_discovery.rs`, `dashboard.rs`, `activation.rs`, `price_intelligence.rs`, `b2b_segmentation.rs`, `activation_orchestrator.rs`) or Rust-only/not-yet-wired per `docs/ROADMAP_HONEST.md` — zero are in a module reachable from the Python API. Re-verified this pass (count unchanged at 30; the pass added zero new clippy warnings despite the pyo3 bump and 18-file rename). | SOURCE_CODE (`cargo clippy`) | OPEN (unchanged) | Already tracked in `docs/ROADMAP_HONEST.md`'s own lint-debt accounting; not re-litigated here. |
|
|
48
48
|
|
|
49
49
|
## Explicit TODOs
|
|
@@ -69,7 +69,7 @@ None found this pass. `actionlint` clean on both workflow files. `tests.yml`'s `
|
|
|
69
69
|
|
|
70
70
|
## Test Debt
|
|
71
71
|
|
|
72
|
-
TD-0008 (benchmark marker warning). Otherwise: 439/439 Rust tests, 227 passed/2 skipped Python tests, both re-verified at the final state after all fixes in this pass.
|
|
72
|
+
TD-0008 (benchmark marker warning) is resolved: the `benchmark` marker is already registered in `pyproject.toml`, so no `PytestUnknownMarkWarning` is emitted. Otherwise: 439/439 Rust tests, 227 passed/2 skipped Python tests, both re-verified at the final state after all fixes in this pass.
|
|
73
73
|
|
|
74
74
|
## Dependency Debt
|
|
75
75
|
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "clusteraudiencekit"
|
|
7
|
-
version = "7.4.
|
|
7
|
+
version = "7.4.2"
|
|
8
8
|
description = "Rust-powered customer segmentation: RFM analysis, KMeans/K-Prototypes clustering, churn prediction, customer lifetime value, real-time streaming segmentation, drift detection, lookalike audiences, cohort analytics, lifecycle tracking, and differential privacy / k-anonymity."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
|