mta-audit 0.1.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.
- mta_audit-0.1.0/.github/workflows/ci.yml +28 -0
- mta_audit-0.1.0/.github/workflows/publish.yml +23 -0
- mta_audit-0.1.0/.gitignore +14 -0
- mta_audit-0.1.0/CHANGELOG.md +30 -0
- mta_audit-0.1.0/LICENSE +21 -0
- mta_audit-0.1.0/PKG-INFO +389 -0
- mta_audit-0.1.0/README.md +334 -0
- mta_audit-0.1.0/benchmarks/__init__.py +1 -0
- mta_audit-0.1.0/benchmarks/criteo_benchmark.py +353 -0
- mta_audit-0.1.0/benchmarks/results/criteo_benchmark.json +253 -0
- mta_audit-0.1.0/benchmarks/results/criteo_benchmark.md +108 -0
- mta_audit-0.1.0/benchmarks/results/criteo_linear_attribution.csv +234 -0
- mta_audit-0.1.0/benchmarks/results/sample_report.html +717 -0
- mta_audit-0.1.0/benchmarks/results/sample_report.md +105 -0
- mta_audit-0.1.0/benchmarks/results/scoring_sensitivity.md +32 -0
- mta_audit-0.1.0/benchmarks/scoring_sensitivity.py +127 -0
- mta_audit-0.1.0/docs/api.md +80 -0
- mta_audit-0.1.0/docs/concepts.md +32 -0
- mta_audit-0.1.0/docs/methodology.md +156 -0
- mta_audit-0.1.0/docs/practitioner-review.md +27 -0
- mta_audit-0.1.0/docs/releasing.md +41 -0
- mta_audit-0.1.0/docs/stability.md +37 -0
- mta_audit-0.1.0/examples/criteo_example.ipynb +368 -0
- mta_audit-0.1.0/examples/quickstart.py +36 -0
- mta_audit-0.1.0/pyproject.toml +92 -0
- mta_audit-0.1.0/src/mta_audit/__init__.py +196 -0
- mta_audit-0.1.0/src/mta_audit/attribution/__init__.py +31 -0
- mta_audit-0.1.0/src/mta_audit/attribution/base.py +110 -0
- mta_audit-0.1.0/src/mta_audit/attribution/first_touch.py +5 -0
- mta_audit-0.1.0/src/mta_audit/attribution/last_touch.py +5 -0
- mta_audit-0.1.0/src/mta_audit/attribution/linear.py +5 -0
- mta_audit-0.1.0/src/mta_audit/attribution/markov.py +291 -0
- mta_audit-0.1.0/src/mta_audit/attribution/rules.py +33 -0
- mta_audit-0.1.0/src/mta_audit/audit.py +557 -0
- mta_audit-0.1.0/src/mta_audit/audits/__init__.py +83 -0
- mta_audit-0.1.0/src/mta_audit/audits/channel_concentration.py +117 -0
- mta_audit-0.1.0/src/mta_audit/audits/concentration.py +15 -0
- mta_audit-0.1.0/src/mta_audit/audits/contamination.py +178 -0
- mta_audit-0.1.0/src/mta_audit/audits/conversion_window.py +243 -0
- mta_audit-0.1.0/src/mta_audit/audits/data_quality.py +13 -0
- mta_audit-0.1.0/src/mta_audit/audits/exposure.py +189 -0
- mta_audit-0.1.0/src/mta_audit/audits/identity.py +39 -0
- mta_audit-0.1.0/src/mta_audit/audits/leakage.py +267 -0
- mta_audit-0.1.0/src/mta_audit/audits/model_disagreement.py +152 -0
- mta_audit-0.1.0/src/mta_audit/audits/model_stability.py +217 -0
- mta_audit-0.1.0/src/mta_audit/audits/path_quality.py +12 -0
- mta_audit-0.1.0/src/mta_audit/audits/path_sparsity.py +97 -0
- mta_audit-0.1.0/src/mta_audit/bootstrap.py +195 -0
- mta_audit-0.1.0/src/mta_audit/checks.py +476 -0
- mta_audit-0.1.0/src/mta_audit/core.py +30 -0
- mta_audit-0.1.0/src/mta_audit/datasets/__init__.py +58 -0
- mta_audit-0.1.0/src/mta_audit/datasets/criteo.py +331 -0
- mta_audit-0.1.0/src/mta_audit/datasets/evaluation.py +47 -0
- mta_audit-0.1.0/src/mta_audit/datasets/external.py +431 -0
- mta_audit-0.1.0/src/mta_audit/datasets/scenarios.py +149 -0
- mta_audit-0.1.0/src/mta_audit/datasets/synthetic.py +168 -0
- mta_audit-0.1.0/src/mta_audit/journeys.py +423 -0
- mta_audit-0.1.0/src/mta_audit/py.typed +1 -0
- mta_audit-0.1.0/src/mta_audit/results.py +647 -0
- mta_audit-0.1.0/src/mta_audit/robustness.py +341 -0
- mta_audit-0.1.0/src/mta_audit/sampling.py +96 -0
- mta_audit-0.1.0/src/mta_audit/schema.py +190 -0
- mta_audit-0.1.0/src/mta_audit/scoring.py +157 -0
- mta_audit-0.1.0/src/mta_audit/simulation/__init__.py +17 -0
- mta_audit-0.1.0/src/mta_audit/simulation/corruption.py +450 -0
- mta_audit-0.1.0/src/mta_audit/utils/__init__.py +10 -0
- mta_audit-0.1.0/src/mta_audit/utils/validation.py +5 -0
- mta_audit-0.1.0/src/mta_audit/visualization/__init__.py +19 -0
- mta_audit-0.1.0/src/mta_audit/visualization/plots.py +128 -0
- mta_audit-0.1.0/tests/conftest.py +14 -0
- mta_audit-0.1.0/tests/fixtures/criteo_mini.tsv +7 -0
- mta_audit-0.1.0/tests/fixtures/ignazio_mini.csv +6 -0
- mta_audit-0.1.0/tests/fixtures/triangulation_mini.csv +4 -0
- mta_audit-0.1.0/tests/integration/test_criteo.py +86 -0
- mta_audit-0.1.0/tests/test_attribution.py +42 -0
- mta_audit-0.1.0/tests/test_audit.py +57 -0
- mta_audit-0.1.0/tests/test_contract_hardening.py +142 -0
- mta_audit-0.1.0/tests/test_criteo_adapter.py +79 -0
- mta_audit-0.1.0/tests/test_external_synthetics.py +97 -0
- mta_audit-0.1.0/tests/test_journeys.py +65 -0
- mta_audit-0.1.0/tests/test_phase2.py +107 -0
- mta_audit-0.1.0/tests/test_phase3.py +106 -0
- mta_audit-0.1.0/tests/test_phase4.py +178 -0
- mta_audit-0.1.0/tests/test_phase5.py +108 -0
- mta_audit-0.1.0/tests/test_schema.py +54 -0
- mta_audit-0.1.0/tests/test_scoring_sensitivity.py +33 -0
- mta_audit-0.1.0/tests/test_uncertainty_robustness.py +378 -0
- mta_audit-0.1.0/tests/test_v02_readiness.py +138 -0
- mta_audit-0.1.0/uv.lock +1458 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
cache: pip
|
|
23
|
+
- run: python -m pip install --upgrade pip
|
|
24
|
+
- run: python -m pip install -e ".[dev]"
|
|
25
|
+
- run: pytest
|
|
26
|
+
- run: ruff check src tests
|
|
27
|
+
- if: matrix.python-version == '3.11'
|
|
28
|
+
run: mypy
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
environment: pypi
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.11"
|
|
21
|
+
- run: python -m pip install --upgrade pip build
|
|
22
|
+
- run: python -m build
|
|
23
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes follow [Keep a Changelog](https://keepachangelog.com/) conventions.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-09-15
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Add a standalone Python library for auditing observational multi-touch
|
|
10
|
+
attribution reliability.
|
|
11
|
+
- Add typed event validation and converter/non-converter journey construction.
|
|
12
|
+
- Add first-touch, last-touch, linear, and absorbing Markov attribution.
|
|
13
|
+
- Add data-quality, duplicate, path, window, identity-loss, touchpoint-loss,
|
|
14
|
+
temporal-stability, and model-disagreement checks.
|
|
15
|
+
- Add deterministic journey-level bootstrap attribution intervals and rank frequencies.
|
|
16
|
+
- Add decision robustness and rank/share assumption-sensitivity matrices.
|
|
17
|
+
- Add typed insufficient-evidence statuses that abstain from aggregate scoring.
|
|
18
|
+
- Add six deterministic known-condition stress scenarios.
|
|
19
|
+
- Add standalone Markdown and HTML reports.
|
|
20
|
+
- Add complete-user sampling with report-visible metadata.
|
|
21
|
+
- Add public Criteo and Hugging Face synthetic dataset adapters.
|
|
22
|
+
- Add independent JD-style and Criteo Research label-mismatch synthetic generators.
|
|
23
|
+
- Add a Poisson multi-touch synthesizer compatible with the PubliusV CSV schema.
|
|
24
|
+
- Add optional adapters for IgnazioDS journeys and triangulation user-level MTA tables.
|
|
25
|
+
- Identify Markov only when NULL/non-converter paths are observed.
|
|
26
|
+
- Score identity robustness in the default audit run.
|
|
27
|
+
- Treat date-grain repeated touches as informational, not duplicate failures.
|
|
28
|
+
- Fail data quality when converting events have zero conversion value.
|
|
29
|
+
- Add transparent configurable scoring weights, interpretation bands, and a
|
|
30
|
+
reproducible score-sensitivity benchmark.
|
mta_audit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mta-audit 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.
|
mta_audit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: mta-audit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reliability audits for multi-touch attribution data and models.
|
|
5
|
+
Project-URL: Homepage, https://github.com/morantejr/mta-audit
|
|
6
|
+
Project-URL: Documentation, https://github.com/morantejr/mta-audit/tree/main/docs
|
|
7
|
+
Project-URL: Issues, https://github.com/morantejr/mta-audit/issues
|
|
8
|
+
Author: mta-audit contributors
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 mta-audit contributors
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: attribution,audit,data-quality,marketing-analytics
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
38
|
+
Classifier: Typing :: Typed
|
|
39
|
+
Requires-Python: >=3.11
|
|
40
|
+
Requires-Dist: numpy>=1.26
|
|
41
|
+
Requires-Dist: pandas>=2.1
|
|
42
|
+
Provides-Extra: dev
|
|
43
|
+
Requires-Dist: matplotlib>=3.8; extra == 'dev'
|
|
44
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
45
|
+
Requires-Dist: pandas-stubs>=2.1; extra == 'dev'
|
|
46
|
+
Requires-Dist: pyarrow>=15; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
48
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
49
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
50
|
+
Provides-Extra: parquet
|
|
51
|
+
Requires-Dist: pyarrow>=15; extra == 'parquet'
|
|
52
|
+
Provides-Extra: viz
|
|
53
|
+
Requires-Dist: matplotlib>=3.8; extra == 'viz'
|
|
54
|
+
Description-Content-Type: text/markdown
|
|
55
|
+
|
|
56
|
+
# mta-audit
|
|
57
|
+
|
|
58
|
+
**Stress-testing and reliability testing for multi-touch attribution.**
|
|
59
|
+
|
|
60
|
+
`mta-audit` evaluates whether campaign conclusions remain stable when
|
|
61
|
+
attribution windows, identity quality, touchpoint availability, attribution
|
|
62
|
+
models, sampling, and other measurement assumptions change.
|
|
63
|
+
|
|
64
|
+
> It does not estimate causal lift or incrementality.
|
|
65
|
+
|
|
66
|
+
This project is a standalone reliability library. Attribution systems still
|
|
67
|
+
allocate credit; this package scores whether journeys and model outputs are
|
|
68
|
+
stable enough to use.
|
|
69
|
+
|
|
70
|
+
Optional public-dataset adapters only map foreign tables onto the package event
|
|
71
|
+
schema.
|
|
72
|
+
|
|
73
|
+
## What it catches
|
|
74
|
+
|
|
75
|
+
The public Criteo benchmark uses an explicit 8,000-user sample: 21,307 mapped
|
|
76
|
+
events, 639 anonymized campaigns, 8,144 journeys, and 586 conversions.
|
|
77
|
+
|
|
78
|
+
- Injecting 1–10% duplicate events was detected every time and reduced the
|
|
79
|
+
scoped data-quality score from **72.35 to 50.20–50.70**.
|
|
80
|
+
- Conversion-window campaign ranks reached a minimum Spearman correlation of
|
|
81
|
+
**0.588** across 1/3/7/14/30-day windows.
|
|
82
|
+
- Dropping 30% of eligible touchpoints produced **2.2% attribution-share
|
|
83
|
+
drift** and reduced campaign rank correlation to **0.972**.
|
|
84
|
+
- Fragmenting 20% of identities increased journeys from **8,144 to 8,908**.
|
|
85
|
+
|
|
86
|
+
See the [rendered sample audit](benchmarks/results/sample_report.html), its
|
|
87
|
+
[Markdown source](benchmarks/results/sample_report.md), and the full
|
|
88
|
+
[Criteo reliability scorecard](benchmarks/results/criteo_benchmark.md).
|
|
89
|
+
The sample is synthetic and deterministic; the Criteo figures are measured,
|
|
90
|
+
not illustrative.
|
|
91
|
+
|
|
92
|
+
## Installation
|
|
93
|
+
|
|
94
|
+
Python 3.11–3.13 is supported.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install "mta-audit @ git+https://github.com/morantejr/mta-audit.git@v0.1.0"
|
|
98
|
+
pip install "mta-audit[viz] @ git+https://github.com/morantejr/mta-audit.git@v0.1.0"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
PyPI publication is pending its account-side Trusted Publisher registration.
|
|
102
|
+
After that is connected, the shorter command will be `pip install mta-audit`.
|
|
103
|
+
For an unreleased main-branch snapshot:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pip install "mta-audit @ git+https://github.com/morantejr/mta-audit.git"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For contributors: `pip install -e ".[dev]"`.
|
|
110
|
+
|
|
111
|
+
## Quickstart
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
import pandas as pd
|
|
115
|
+
from mta_audit import MTAAudit
|
|
116
|
+
|
|
117
|
+
data = pd.DataFrame({
|
|
118
|
+
"user_id": ["a", "a", "b", "b"],
|
|
119
|
+
"timestamp": pd.to_datetime([
|
|
120
|
+
"2026-01-01", "2026-01-03", "2026-01-02", "2026-01-04"
|
|
121
|
+
]),
|
|
122
|
+
"channel": ["search", "email", "social", "direct"],
|
|
123
|
+
"conversion": [False, True, False, True],
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
report = MTAAudit(data=data).run(
|
|
127
|
+
bootstrap=True,
|
|
128
|
+
n_bootstrap=200,
|
|
129
|
+
random_state=42,
|
|
130
|
+
)
|
|
131
|
+
print(report.summary())
|
|
132
|
+
print(report.decision_robustness())
|
|
133
|
+
report.sensitivity_matrix(metric="rank")
|
|
134
|
+
report.to_dataframe()
|
|
135
|
+
report.to_json()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Example output:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
MTA Audit Reliability Report
|
|
142
|
+
Overall audit score: 67.5/100 — Fragile
|
|
143
|
+
Component scores:
|
|
144
|
+
- Data Quality: …
|
|
145
|
+
- Window Stability: …
|
|
146
|
+
- Identity Robustness: …
|
|
147
|
+
- Path Quality: …
|
|
148
|
+
- Model Agreement: …
|
|
149
|
+
- Temporal Stability: insufficient evidence
|
|
150
|
+
Checks run: 12 | Visible findings: 7
|
|
151
|
+
Markov removal effects: not evaluated
|
|
152
|
+
Channel grain: channel
|
|
153
|
+
|
|
154
|
+
Decision robustness:
|
|
155
|
+
Search remains top-two in 94% of tested scenarios.
|
|
156
|
+
Display and Social frequently change position; avoid a strong reallocation
|
|
157
|
+
between them based on this observational attribution analysis alone.
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Custom schemas and the advanced API remain concise:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
audit = MTAAudit(
|
|
164
|
+
data=data,
|
|
165
|
+
user_col="visitor_id",
|
|
166
|
+
timestamp_col="event_time",
|
|
167
|
+
channel_col="source",
|
|
168
|
+
conversion_col="converted",
|
|
169
|
+
scoring_weights={"data_quality": 2, "model_agreement": 1},
|
|
170
|
+
)
|
|
171
|
+
report = audit.run(
|
|
172
|
+
attribution_models=["first_touch", "last_touch", "linear", "markov"],
|
|
173
|
+
conversion_windows=[7, 14, 30, 60],
|
|
174
|
+
checks=["data_quality", "conversion_window", "model_disagreement"],
|
|
175
|
+
simulations={"identity_loss": {"rates": [0.05, 0.10, 0.20]}},
|
|
176
|
+
bootstrap=True,
|
|
177
|
+
n_bootstrap=500,
|
|
178
|
+
random_state=42,
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
For reusable bootstrap settings:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from mta_audit import BootstrapConfig
|
|
186
|
+
|
|
187
|
+
report = MTAAudit(data).run(
|
|
188
|
+
bootstrap=BootstrapConfig(
|
|
189
|
+
n_iterations=500,
|
|
190
|
+
confidence_level=0.90,
|
|
191
|
+
random_state=42,
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
report.bootstrap.to_dataframe()
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Bootstrap resamples complete journeys, never touchpoint rows. Its percentile
|
|
198
|
+
intervals and rank frequencies measure observational attribution stability;
|
|
199
|
+
they are not causal confidence intervals.
|
|
200
|
+
|
|
201
|
+
## Checks
|
|
202
|
+
|
|
203
|
+
- Required fields, nulls, timestamps, channels, and duplicate events
|
|
204
|
+
- Conversion-window sensitivity and delayed-converter contamination
|
|
205
|
+
- First-touch, last-touch, linear, and absorbing Markov model disagreement
|
|
206
|
+
- Path sparsity and channel concentration
|
|
207
|
+
- Weekly or monthly temporal stability
|
|
208
|
+
- Converter/non-converter exposure comparison
|
|
209
|
+
- Deterministic identity, touchpoint, impression, and click-loss simulations
|
|
210
|
+
|
|
211
|
+
## Methodology
|
|
212
|
+
|
|
213
|
+
Every audit emits a normalized 0–100 **audit robustness score**, severity,
|
|
214
|
+
observed metric, and recommendation. The score does not mean percent correct.
|
|
215
|
+
Related checks feed six reliability components:
|
|
216
|
+
`data_quality`, `window_stability`, `identity_robustness`, `path_quality`,
|
|
217
|
+
`model_agreement`, and `temporal_stability`. The overall formula is:
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
reliability = Σ(component score × normalized available-component weight)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Only completed components are included; skipped checks are never treated as
|
|
224
|
+
perfect. Attribution models allocate observed conversion value. Markov credit
|
|
225
|
+
uses channel-removal effects from an absorbing transition chain.
|
|
226
|
+
|
|
227
|
+
Qualitative bands are Robust (90–100), Stable (80–89), Caution (70–79),
|
|
228
|
+
Fragile (60–69), and Highly Fragile (<60). The component scorecard is more
|
|
229
|
+
important than the aggregate.
|
|
230
|
+
|
|
231
|
+
## Shareable reports and local sampling
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
markdown = report.to_markdown()
|
|
235
|
+
html = report.to_html()
|
|
236
|
+
|
|
237
|
+
from mta_audit import sample_for_audit
|
|
238
|
+
sample = sample_for_audit(data, max_journeys=100_000, random_state=42)
|
|
239
|
+
sampled_report = MTAAudit(sample).run()
|
|
240
|
+
print(sampled_report.sample_info)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Sampling preserves complete user histories and marks the resulting report.
|
|
244
|
+
This remains a local pandas package; no warehouse or distributed execution is
|
|
245
|
+
included.
|
|
246
|
+
|
|
247
|
+
## Thresholds and configuration
|
|
248
|
+
|
|
249
|
+
Default scoring weights are 20%, 15%, 15%, 15%, 20%, and 15% in the component
|
|
250
|
+
order above. Any non-negative relative values can be passed through
|
|
251
|
+
`scoring_weights`; they are normalized automatically over available components.
|
|
252
|
+
These are explicit policy defaults, not empirically estimated constants:
|
|
253
|
+
data quality and model agreement receive 20% because invalid inputs and
|
|
254
|
+
conclusion-changing model choice are direct decision risks; the other four
|
|
255
|
+
dimensions receive equal 15% weights. The round-number bands are likewise
|
|
256
|
+
communication thresholds, not confidence intervals.
|
|
257
|
+
|
|
258
|
+
The reproducible [score-policy sensitivity report](benchmarks/results/scoring_sensitivity.md)
|
|
259
|
+
reweights the committed Criteo components and shifts every rating cutoff by
|
|
260
|
+
five points. It shows how much the aggregate and label depend on those policy
|
|
261
|
+
choices. Component scores must remain visible; users should override weights
|
|
262
|
+
when their decision context differs.
|
|
263
|
+
Audit-specific threshold dataclasses such as `ConversionWindowThresholds`,
|
|
264
|
+
`ContaminationThresholds`, and `TemporalStabilityThresholds` expose warning
|
|
265
|
+
cutoffs. See [the methodology](docs/methodology.md) for formulas.
|
|
266
|
+
|
|
267
|
+
## Visualization
|
|
268
|
+
|
|
269
|
+
With the `viz` extra installed, reports provide `plot_scorecard()`,
|
|
270
|
+
`plot_model_comparison()`, `plot_window_sensitivity()`, and
|
|
271
|
+
`plot_channel_volatility()`. Each returns a matplotlib `Axes`.
|
|
272
|
+
|
|
273
|
+
## Limitations
|
|
274
|
+
|
|
275
|
+
Results depend on identity resolution, channel taxonomy, event collection, and
|
|
276
|
+
the selected lookback/conversion windows. Sparse paths make transition estimates
|
|
277
|
+
unstable. Converter/non-converter comparisons are confounded and are not lift
|
|
278
|
+
estimates. Tracking-loss simulations test sensitivity to specified corruption,
|
|
279
|
+
not the true unknown missingness process.
|
|
280
|
+
|
|
281
|
+
Converter-only sequencing tables do **not** identify Markov removal effects.
|
|
282
|
+
The report sets `markov_identified=false` in that case. Date-grain
|
|
283
|
+
timestamps are not treated as duplicates. Campaign-name "channels" are flagged as
|
|
284
|
+
fine grain.
|
|
285
|
+
|
|
286
|
+
Kaggle does not currently publish a licensed event-level multi-touch path dataset
|
|
287
|
+
with converters and non-converters comparable to Criteo. Public fixtures:
|
|
288
|
+
|
|
289
|
+
- Criteo Attribution Modeling (real impressions; see walkthrough below)
|
|
290
|
+
- Hugging Face [synthetic attribution benchmark](https://huggingface.co/datasets/lucianfialho/synthetic-attribution-benchmark) (CC BY 4.0)
|
|
291
|
+
- Independent generators inspired by JD MTA (Du et al., 2019) and Criteo Research
|
|
292
|
+
robust-label experiments (Bompaire et al., 2020): `simulate_jd_mta_events`,
|
|
293
|
+
`simulate_criteo_label_events`, `simulate_synthesizer_events`
|
|
294
|
+
- Optional CSV adapters for IgnazioDS journeys and the triangulation project's
|
|
295
|
+
user-level `df_mta.csv` (`load_ignazio_attribution`, `load_triangulation_mta`).
|
|
296
|
+
Those files are not stored in git. Weekly MMM / geo tables are out of scope.
|
|
297
|
+
|
|
298
|
+
## Roadmap
|
|
299
|
+
|
|
300
|
+
Current stage: **0.1.0 alpha**. Next:
|
|
301
|
+
|
|
302
|
+
1. Keep 0.1.x installable and documented (stability contract in
|
|
303
|
+
[docs/stability.md](docs/stability.md)).
|
|
304
|
+
2. **Beta** when `run()` / report fields stay boring across a few tagged
|
|
305
|
+
releases and the Criteo reference scorecard is re-run before each tag.
|
|
306
|
+
3. **1.0** when scoring defaults are frozen and third parties can depend on
|
|
307
|
+
the public API. Warehouse extracts stay out of this repository.
|
|
308
|
+
|
|
309
|
+
Later, optional work: more public-dataset adapters and richer performance
|
|
310
|
+
benchmarks.
|
|
311
|
+
|
|
312
|
+
See [concepts](docs/concepts.md), [methodology](docs/methodology.md),
|
|
313
|
+
[API reference](docs/api.md), [stability](docs/stability.md),
|
|
314
|
+
[releasing](docs/releasing.md), the
|
|
315
|
+
[external practitioner review protocol](docs/practitioner-review.md), and
|
|
316
|
+
[examples](examples/quickstart.py).
|
|
317
|
+
|
|
318
|
+
## Criteo walkthrough
|
|
319
|
+
|
|
320
|
+
The public Criteo Attribution Modeling dataset (CC-BY-NC-SA-4.0) is the
|
|
321
|
+
real-world integration set for this package. **It is not stored in git.**
|
|
322
|
+
|
|
323
|
+
1. Download `criteo_attribution_dataset.tsv.gz` from
|
|
324
|
+
[Hugging Face](https://huggingface.co/datasets/criteo/criteo-attribution-dataset)
|
|
325
|
+
(Criteo's published copy of Diemert et al., 2017).
|
|
326
|
+
2. Save it as `./data/criteo_attribution_dataset.tsv.gz`, or let the loader
|
|
327
|
+
cache it under `~/.cache/mta-audit/` with `download=True`.
|
|
328
|
+
3. Map impressions through the adapter — do **not** pass Criteo's impression-level
|
|
329
|
+
`conversion` flag straight into `conversion_col`.
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
from mta_audit import MTAAudit
|
|
333
|
+
from mta_audit.datasets import load_criteo_attribution, CriteoAttributionAdapter
|
|
334
|
+
|
|
335
|
+
# Explicit representative sample; pass sample_users=None for the full file.
|
|
336
|
+
df = load_criteo_attribution(path="./data/criteo_attribution_dataset.tsv.gz", sample_users=20000)
|
|
337
|
+
# equivalent: CriteoAttributionAdapter("./data/criteo_attribution_dataset.tsv.gz").load()
|
|
338
|
+
|
|
339
|
+
report = MTAAudit(data=df).run(
|
|
340
|
+
attribution_models=["first_touch", "last_touch", "linear", "markov"]
|
|
341
|
+
)
|
|
342
|
+
print(report.summary())
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Public synthetic journeys (named channels + NULL paths, CC BY 4.0):
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
from mta_audit.datasets import load_synthetic_attribution
|
|
349
|
+
|
|
350
|
+
events = load_synthetic_attribution(download=True)
|
|
351
|
+
report = MTAAudit(data=events).run(attribution_models=["linear", "markov"])
|
|
352
|
+
print(report.markov_identified)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Independent research-style synthetics (no third-party generators vendored):
|
|
356
|
+
|
|
357
|
+
```python
|
|
358
|
+
from mta_audit.datasets import (
|
|
359
|
+
simulate_criteo_label_events,
|
|
360
|
+
simulate_jd_mta_events,
|
|
361
|
+
simulate_synthesizer_events,
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
jd = simulate_jd_mta_events(n_users=200, random_state=42)
|
|
365
|
+
labels = simulate_criteo_label_events(n_users=400, random_state=42)
|
|
366
|
+
synth = simulate_synthesizer_events(n_users=300, random_state=42)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Unit tests never require the file. Integration tests and the benchmark do:
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
pytest # default, no Criteo download
|
|
373
|
+
pytest -m criteo # loads the local/public dataset
|
|
374
|
+
python benchmarks/criteo_benchmark.py --download --sample-users 20000
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Results from a completed run (8,000-user explicit sample) live in
|
|
378
|
+
[`benchmarks/results/criteo_benchmark.md`](benchmarks/results/criteo_benchmark.md).
|
|
379
|
+
On that run, injected duplicates dropped the data-quality score from ~72 to ~50,
|
|
380
|
+
20% identity loss raised journey count from 8,144 to 8,908, and conversion-window
|
|
381
|
+
ranks correlated at only 0.59. The notebook `examples/criteo_example.ipynb` is
|
|
382
|
+
the measurement-team walkthrough.
|
|
383
|
+
|
|
384
|
+
Criteo campaigns are anonymized. Treat outputs as campaign-level attribution
|
|
385
|
+
reliability diagnostics, not named-channel budget recommendations.
|
|
386
|
+
|
|
387
|
+
Removal-effect Markov on ~700 campaigns is implemented with a numpy transition
|
|
388
|
+
matrix. `MarkovAttribution(max_channels=N)` can explicitly collapse a long tail
|
|
389
|
+
into `__OTHER__`; the benchmark does **not** do that by default.
|