proxyml 0.2.2__tar.gz → 0.3.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.
- {proxyml-0.2.2 → proxyml-0.3.0}/PKG-INFO +29 -8
- {proxyml-0.2.2 → proxyml-0.3.0}/README.md +25 -7
- {proxyml-0.2.2 → proxyml-0.3.0}/pyproject.toml +7 -3
- {proxyml-0.2.2 → proxyml-0.3.0}/src/proxyml/__init__.py +3 -9
- {proxyml-0.2.2 → proxyml-0.3.0}/src/proxyml/client.py +93 -20
- proxyml-0.3.0/src/proxyml/local/__init__.py +24 -0
- proxyml-0.3.0/src/proxyml/local/challenger.py +247 -0
- proxyml-0.3.0/src/proxyml/schema_builder.py +67 -0
- {proxyml-0.2.2 → proxyml-0.3.0}/src/proxyml.egg-info/PKG-INFO +29 -8
- {proxyml-0.2.2 → proxyml-0.3.0}/src/proxyml.egg-info/SOURCES.txt +6 -2
- {proxyml-0.2.2 → proxyml-0.3.0}/src/proxyml.egg-info/requires.txt +4 -0
- {proxyml-0.2.2 → proxyml-0.3.0}/tests/test_client.py +117 -13
- proxyml-0.3.0/tests/test_dependency_boundaries.py +89 -0
- proxyml-0.3.0/tests/test_local_challenger.py +155 -0
- proxyml-0.3.0/tests/test_schema_builder.py +57 -0
- proxyml-0.2.2/src/proxyml/schema.py +0 -100
- proxyml-0.2.2/tests/test_schema.py +0 -81
- {proxyml-0.2.2 → proxyml-0.3.0}/LICENSE +0 -0
- {proxyml-0.2.2 → proxyml-0.3.0}/setup.cfg +0 -0
- {proxyml-0.2.2 → proxyml-0.3.0}/src/proxyml.egg-info/dependency_links.txt +0 -0
- {proxyml-0.2.2 → proxyml-0.3.0}/src/proxyml.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: proxyml
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python SDK for calling the ProxyML API
|
|
5
5
|
Author-email: ProxyML <contact@proxyml.ai>
|
|
6
6
|
License: Apache License
|
|
@@ -209,6 +209,9 @@ Requires-Dist: requests>=2.28
|
|
|
209
209
|
Requires-Dist: numpy>=1.23
|
|
210
210
|
Requires-Dist: pandas>=1.5
|
|
211
211
|
Requires-Dist: orjson>=3.9
|
|
212
|
+
Requires-Dist: proxyml-core>=0.1
|
|
213
|
+
Provides-Extra: local
|
|
214
|
+
Requires-Dist: proxyml-core[modeling]>=0.1; extra == "local"
|
|
212
215
|
Provides-Extra: dev
|
|
213
216
|
Requires-Dist: build; extra == "dev"
|
|
214
217
|
Requires-Dist: twine; extra == "dev"
|
|
@@ -236,6 +239,12 @@ statistics are uploaded — your data stays yours.
|
|
|
236
239
|
pip install proxyml
|
|
237
240
|
```
|
|
238
241
|
|
|
242
|
+
Want to train a challenger model locally, with no round-trip to the API? Install the `local` extra (adds scikit-learn and scipy):
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
pip install 'proxyml[local]'
|
|
246
|
+
```
|
|
247
|
+
|
|
239
248
|
## Setup
|
|
240
249
|
|
|
241
250
|
ProxyML requires an API key. Set it as an environment variable before importing the package:
|
|
@@ -261,11 +270,12 @@ from proxyml import get_schema
|
|
|
261
270
|
df = pd.read_csv("data.csv")
|
|
262
271
|
schema = get_schema(df, immutable_cols=["age", "gender"])
|
|
263
272
|
|
|
264
|
-
# 2. Upload the schema
|
|
265
|
-
|
|
273
|
+
# 2. Upload the schema under a name — synthesis and training reference it by name
|
|
274
|
+
SCHEMA_NAME = "my_schema"
|
|
275
|
+
proxyml.put_schema(schema, name=SCHEMA_NAME)
|
|
266
276
|
|
|
267
277
|
# 3. Generate synthetic training data
|
|
268
|
-
synth_df = proxyml.synthesize_data(num_points=500)
|
|
278
|
+
synth_df = proxyml.synthesize_data(num_points=500, schema_name=SCHEMA_NAME)
|
|
269
279
|
|
|
270
280
|
# 4. Score synthetic data with your black-box model
|
|
271
281
|
predictions = my_model.predict(synth_df.values.tolist())
|
|
@@ -275,6 +285,7 @@ proxyml.train_surrogate(
|
|
|
275
285
|
samples=synth_df.values.tolist(),
|
|
276
286
|
predictions=predictions,
|
|
277
287
|
feature_names=list(synth_df.columns),
|
|
288
|
+
schema_name=SCHEMA_NAME,
|
|
278
289
|
)
|
|
279
290
|
|
|
280
291
|
# 6. Find a counterfactual explanation
|
|
@@ -301,6 +312,8 @@ See [`docs/quickstart.md`](docs/quickstart.md) for a full walkthrough and [`docs
|
|
|
301
312
|
|
|
302
313
|
**Surrogate model** — A fast, interpretable model trained to approximate your black-box model's behavior on synthetic data. Once trained, it can be queried directly via the ProxyML API.
|
|
303
314
|
|
|
315
|
+
**Challenger model** — Trained the same way as a surrogate, but locally (`proxyml.local`, no round-trip to the API) and against either real ground-truth labels (a genuine challenger to compare against a champion model) or a black box's predictions (a surrogate/explainer). Its export is structurally identical to a server-trained surrogate's, so the two can be compared and scored with the exact same arithmetic.
|
|
316
|
+
|
|
304
317
|
**Counterfactual explanation** — Given a prediction, a counterfactual is the minimal change to input features that would produce a different prediction. It answers: *"What would have to be different for the outcome to change?"*
|
|
305
318
|
|
|
306
319
|
**Schema** — Describes the statistical properties of each feature (type, range, distribution). Used to generate realistic synthetic data and constrain counterfactual search.
|
|
@@ -309,13 +322,17 @@ See [`docs/quickstart.md`](docs/quickstart.md) for a full walkthrough and [`docs
|
|
|
309
322
|
|
|
310
323
|
| Function | Description |
|
|
311
324
|
|---|---|
|
|
312
|
-
| `get_schema(df, immutable_cols)` |
|
|
313
|
-
| `put_schema(schema)` | Upload a schema to the API |
|
|
314
|
-
| `synthesize_data(num_points, sample, as_df)` | Generate synthetic data points |
|
|
315
|
-
| `train_surrogate(samples, predictions, feature_names, task, test_size)` | Train a surrogate model |
|
|
325
|
+
| `get_schema(df, immutable_cols)` | Infer a `FeatureSchema` from a DataFrame |
|
|
326
|
+
| `put_schema(schema, name)` | Upload a schema to the API under a name |
|
|
327
|
+
| `synthesize_data(num_points, sample, as_df, schema_name)` | Generate synthetic data points |
|
|
328
|
+
| `train_surrogate(samples, predictions, feature_names, task, test_size, schema_name)` | Train a surrogate model |
|
|
329
|
+
| `train_auto_surrogate(data, target_col, ...)` | Load data + train a surrogate in one call, skipping synthesis |
|
|
330
|
+
| `export_surrogate(version)` | Export a surrogate for offline scoring via `predict_from_export` |
|
|
316
331
|
| `predict(sample, version)` | Score a single sample with the surrogate model |
|
|
317
332
|
| `find_counterfactual(sample, target, ...)` | Find a counterfactual for a given sample |
|
|
318
333
|
| `interpret_counterfactual(sample, counterfactual, ...)` | Generate a human-readable explanation |
|
|
334
|
+
| `proxyml.local.train_challenger(df, target, schema, ...)` | Train a challenger model locally — no API round-trip (`pip install 'proxyml[local]'`) |
|
|
335
|
+
| `proxyml.local.train_auto_challenger(data, target_col, ...)` | Load data + train a local challenger in one call |
|
|
319
336
|
|
|
320
337
|
Full documentation: [`docs/api.md`](docs/api.md)
|
|
321
338
|
|
|
@@ -323,6 +340,10 @@ Full documentation: [`docs/api.md`](docs/api.md)
|
|
|
323
340
|
|
|
324
341
|
- [`examples/basic_usage.py`](examples/basic_usage.py) — Schema upload, data synthesis, surrogate training
|
|
325
342
|
- [`examples/counterfactual_example.py`](examples/counterfactual_example.py) — Counterfactual search and interpretation
|
|
343
|
+
- [`examples/regression_example.py`](examples/regression_example.py) — Regression with immutable features
|
|
344
|
+
- [`examples/multiclass_example.py`](examples/multiclass_example.py) — Multi-class classification with per-class feature importances
|
|
345
|
+
- [`examples/testing_example.py`](examples/testing_example.py) — Using a surrogate as a reference model in CI
|
|
346
|
+
- [`examples/surrogate_export_example.py`](examples/surrogate_export_example.py) — Exporting a surrogate and reproducing its predictions locally
|
|
326
347
|
|
|
327
348
|
## License
|
|
328
349
|
|
|
@@ -17,6 +17,12 @@ statistics are uploaded — your data stays yours.
|
|
|
17
17
|
pip install proxyml
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
Want to train a challenger model locally, with no round-trip to the API? Install the `local` extra (adds scikit-learn and scipy):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install 'proxyml[local]'
|
|
24
|
+
```
|
|
25
|
+
|
|
20
26
|
## Setup
|
|
21
27
|
|
|
22
28
|
ProxyML requires an API key. Set it as an environment variable before importing the package:
|
|
@@ -42,11 +48,12 @@ from proxyml import get_schema
|
|
|
42
48
|
df = pd.read_csv("data.csv")
|
|
43
49
|
schema = get_schema(df, immutable_cols=["age", "gender"])
|
|
44
50
|
|
|
45
|
-
# 2. Upload the schema
|
|
46
|
-
|
|
51
|
+
# 2. Upload the schema under a name — synthesis and training reference it by name
|
|
52
|
+
SCHEMA_NAME = "my_schema"
|
|
53
|
+
proxyml.put_schema(schema, name=SCHEMA_NAME)
|
|
47
54
|
|
|
48
55
|
# 3. Generate synthetic training data
|
|
49
|
-
synth_df = proxyml.synthesize_data(num_points=500)
|
|
56
|
+
synth_df = proxyml.synthesize_data(num_points=500, schema_name=SCHEMA_NAME)
|
|
50
57
|
|
|
51
58
|
# 4. Score synthetic data with your black-box model
|
|
52
59
|
predictions = my_model.predict(synth_df.values.tolist())
|
|
@@ -56,6 +63,7 @@ proxyml.train_surrogate(
|
|
|
56
63
|
samples=synth_df.values.tolist(),
|
|
57
64
|
predictions=predictions,
|
|
58
65
|
feature_names=list(synth_df.columns),
|
|
66
|
+
schema_name=SCHEMA_NAME,
|
|
59
67
|
)
|
|
60
68
|
|
|
61
69
|
# 6. Find a counterfactual explanation
|
|
@@ -82,6 +90,8 @@ See [`docs/quickstart.md`](docs/quickstart.md) for a full walkthrough and [`docs
|
|
|
82
90
|
|
|
83
91
|
**Surrogate model** — A fast, interpretable model trained to approximate your black-box model's behavior on synthetic data. Once trained, it can be queried directly via the ProxyML API.
|
|
84
92
|
|
|
93
|
+
**Challenger model** — Trained the same way as a surrogate, but locally (`proxyml.local`, no round-trip to the API) and against either real ground-truth labels (a genuine challenger to compare against a champion model) or a black box's predictions (a surrogate/explainer). Its export is structurally identical to a server-trained surrogate's, so the two can be compared and scored with the exact same arithmetic.
|
|
94
|
+
|
|
85
95
|
**Counterfactual explanation** — Given a prediction, a counterfactual is the minimal change to input features that would produce a different prediction. It answers: *"What would have to be different for the outcome to change?"*
|
|
86
96
|
|
|
87
97
|
**Schema** — Describes the statistical properties of each feature (type, range, distribution). Used to generate realistic synthetic data and constrain counterfactual search.
|
|
@@ -90,13 +100,17 @@ See [`docs/quickstart.md`](docs/quickstart.md) for a full walkthrough and [`docs
|
|
|
90
100
|
|
|
91
101
|
| Function | Description |
|
|
92
102
|
|---|---|
|
|
93
|
-
| `get_schema(df, immutable_cols)` |
|
|
94
|
-
| `put_schema(schema)` | Upload a schema to the API |
|
|
95
|
-
| `synthesize_data(num_points, sample, as_df)` | Generate synthetic data points |
|
|
96
|
-
| `train_surrogate(samples, predictions, feature_names, task, test_size)` | Train a surrogate model |
|
|
103
|
+
| `get_schema(df, immutable_cols)` | Infer a `FeatureSchema` from a DataFrame |
|
|
104
|
+
| `put_schema(schema, name)` | Upload a schema to the API under a name |
|
|
105
|
+
| `synthesize_data(num_points, sample, as_df, schema_name)` | Generate synthetic data points |
|
|
106
|
+
| `train_surrogate(samples, predictions, feature_names, task, test_size, schema_name)` | Train a surrogate model |
|
|
107
|
+
| `train_auto_surrogate(data, target_col, ...)` | Load data + train a surrogate in one call, skipping synthesis |
|
|
108
|
+
| `export_surrogate(version)` | Export a surrogate for offline scoring via `predict_from_export` |
|
|
97
109
|
| `predict(sample, version)` | Score a single sample with the surrogate model |
|
|
98
110
|
| `find_counterfactual(sample, target, ...)` | Find a counterfactual for a given sample |
|
|
99
111
|
| `interpret_counterfactual(sample, counterfactual, ...)` | Generate a human-readable explanation |
|
|
112
|
+
| `proxyml.local.train_challenger(df, target, schema, ...)` | Train a challenger model locally — no API round-trip (`pip install 'proxyml[local]'`) |
|
|
113
|
+
| `proxyml.local.train_auto_challenger(data, target_col, ...)` | Load data + train a local challenger in one call |
|
|
100
114
|
|
|
101
115
|
Full documentation: [`docs/api.md`](docs/api.md)
|
|
102
116
|
|
|
@@ -104,6 +118,10 @@ Full documentation: [`docs/api.md`](docs/api.md)
|
|
|
104
118
|
|
|
105
119
|
- [`examples/basic_usage.py`](examples/basic_usage.py) — Schema upload, data synthesis, surrogate training
|
|
106
120
|
- [`examples/counterfactual_example.py`](examples/counterfactual_example.py) — Counterfactual search and interpretation
|
|
121
|
+
- [`examples/regression_example.py`](examples/regression_example.py) — Regression with immutable features
|
|
122
|
+
- [`examples/multiclass_example.py`](examples/multiclass_example.py) — Multi-class classification with per-class feature importances
|
|
123
|
+
- [`examples/testing_example.py`](examples/testing_example.py) — Using a surrogate as a reference model in CI
|
|
124
|
+
- [`examples/surrogate_export_example.py`](examples/surrogate_export_example.py) — Exporting a surrogate and reproducing its predictions locally
|
|
107
125
|
|
|
108
126
|
## License
|
|
109
127
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "proxyml"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Python SDK for calling the ProxyML API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {file = "LICENSE"}
|
|
@@ -30,15 +30,19 @@ dependencies = [
|
|
|
30
30
|
"numpy>=1.23",
|
|
31
31
|
"pandas>=1.5",
|
|
32
32
|
"orjson>=3.9",
|
|
33
|
+
"proxyml-core>=0.1",
|
|
33
34
|
]
|
|
34
35
|
|
|
35
36
|
[project.optional-dependencies]
|
|
37
|
+
local = [
|
|
38
|
+
"proxyml-core[modeling]>=0.1",
|
|
39
|
+
]
|
|
36
40
|
dev = [
|
|
37
41
|
"build",
|
|
38
42
|
"twine",
|
|
39
43
|
"pytest",
|
|
40
|
-
"black",
|
|
41
|
-
"ruff",
|
|
44
|
+
"black",
|
|
45
|
+
"ruff",
|
|
42
46
|
]
|
|
43
47
|
|
|
44
48
|
[project.urls]
|
|
@@ -6,6 +6,7 @@ from proxyml.client import (
|
|
|
6
6
|
delete_schema,
|
|
7
7
|
synthesize_data,
|
|
8
8
|
train_surrogate,
|
|
9
|
+
train_auto_surrogate,
|
|
9
10
|
predict,
|
|
10
11
|
predict_batch,
|
|
11
12
|
find_counterfactual,
|
|
@@ -24,12 +25,7 @@ from proxyml.client import (
|
|
|
24
25
|
explain_local_batch,
|
|
25
26
|
update_model,
|
|
26
27
|
)
|
|
27
|
-
from proxyml.
|
|
28
|
-
get_schema,
|
|
29
|
-
gen_continuous_schema,
|
|
30
|
-
gen_categorical_schema,
|
|
31
|
-
gen_discrete_schema,
|
|
32
|
-
)
|
|
28
|
+
from proxyml.schema_builder import get_schema
|
|
33
29
|
|
|
34
30
|
__all__ = [
|
|
35
31
|
"health_check",
|
|
@@ -39,6 +35,7 @@ __all__ = [
|
|
|
39
35
|
"delete_schema",
|
|
40
36
|
"synthesize_data",
|
|
41
37
|
"train_surrogate",
|
|
38
|
+
"train_auto_surrogate",
|
|
42
39
|
"predict",
|
|
43
40
|
"predict_batch",
|
|
44
41
|
"find_counterfactual",
|
|
@@ -57,7 +54,4 @@ __all__ = [
|
|
|
57
54
|
"explain_local_batch",
|
|
58
55
|
"update_model",
|
|
59
56
|
"get_schema",
|
|
60
|
-
"gen_continuous_schema",
|
|
61
|
-
"gen_categorical_schema",
|
|
62
|
-
"gen_discrete_schema",
|
|
63
57
|
]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import Any
|
|
4
5
|
|
|
5
6
|
import orjson
|
|
@@ -8,6 +9,10 @@ import pandas as pd
|
|
|
8
9
|
import requests
|
|
9
10
|
from pandas.api.types import is_float_dtype, is_integer_dtype
|
|
10
11
|
|
|
12
|
+
from proxyml.schema_builder import get_schema
|
|
13
|
+
from proxyml_core.export import SurrogateExport
|
|
14
|
+
from proxyml_core.schema import FeatureSchema
|
|
15
|
+
|
|
11
16
|
logger = logging.getLogger(__name__)
|
|
12
17
|
|
|
13
18
|
_BOOL_STRINGS = {"true", "false"}
|
|
@@ -156,20 +161,20 @@ def delete(endpoint: str) -> requests.models.Response | _ErrorResponse:
|
|
|
156
161
|
return _ErrorResponse()
|
|
157
162
|
|
|
158
163
|
|
|
159
|
-
def put_schema(schema:
|
|
164
|
+
def put_schema(schema: FeatureSchema, name: str) -> FeatureSchema | None:
|
|
160
165
|
"""
|
|
161
166
|
Uploads a data schema.
|
|
162
167
|
|
|
163
168
|
Args:
|
|
164
|
-
schema (
|
|
169
|
+
schema (FeatureSchema): data schema object, e.g. from get_schema()
|
|
165
170
|
name (str): name for the schema.
|
|
166
171
|
Returns:
|
|
167
|
-
|
|
172
|
+
The stored FeatureSchema, or None if the return code was not 200.
|
|
168
173
|
"""
|
|
169
|
-
r = put(endpoint=f'/schema/{name}', payload=schema)
|
|
174
|
+
r = put(endpoint=f'/schema/{name}', payload=schema.to_dict())
|
|
170
175
|
if r.status_code == 200:
|
|
171
176
|
logger.info("Schema '%s' uploaded successfully", name)
|
|
172
|
-
return r.json()
|
|
177
|
+
return FeatureSchema.from_dict(r.json())
|
|
173
178
|
logger.error(
|
|
174
179
|
"Schema upload failed with status %s: %s",
|
|
175
180
|
r.status_code,
|
|
@@ -178,11 +183,14 @@ def put_schema(schema: dict, name: str) -> Any:
|
|
|
178
183
|
return None
|
|
179
184
|
|
|
180
185
|
|
|
181
|
-
def fetch_schema(name: str) ->
|
|
186
|
+
def fetch_schema(name: str) -> FeatureSchema | None:
|
|
182
187
|
"""Retrieve a stored feature schema by name."""
|
|
183
188
|
r = get(endpoint=f'/schema/{name}', params={})
|
|
184
189
|
if r.status_code == 200:
|
|
185
|
-
|
|
190
|
+
payload = r.json()
|
|
191
|
+
if payload.get('schema_warning'):
|
|
192
|
+
logger.warning(payload['schema_warning'])
|
|
193
|
+
return FeatureSchema.from_dict(payload)
|
|
186
194
|
logger.error(
|
|
187
195
|
"Fetch schema failed with status %s: %s",
|
|
188
196
|
r.status_code,
|
|
@@ -323,22 +331,84 @@ def train_surrogate(
|
|
|
323
331
|
return None
|
|
324
332
|
|
|
325
333
|
|
|
326
|
-
def
|
|
334
|
+
def train_auto_surrogate(
|
|
335
|
+
data: str | Path | pd.DataFrame,
|
|
336
|
+
target_col: str,
|
|
337
|
+
feature_names: list[str] | None = None,
|
|
338
|
+
task: str = 'auto',
|
|
339
|
+
test_size: float = 0.2,
|
|
340
|
+
*,
|
|
341
|
+
schema_name: str,
|
|
342
|
+
immutable_cols: list[str] | None = None,
|
|
343
|
+
name: str | None = None,
|
|
344
|
+
comments: str | None = None,
|
|
345
|
+
) -> Any:
|
|
327
346
|
"""
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
347
|
+
Loads data that already contains samples and a target/prediction column,
|
|
348
|
+
infers and uploads a feature schema, and trains a server-side surrogate
|
|
349
|
+
against target_col — all in one call.
|
|
350
|
+
|
|
351
|
+
Assumes `data` already contains the samples you want to train on and the
|
|
352
|
+
value to predict for each one (real ground truth or a black box's
|
|
353
|
+
predictions), so it skips synthesize_data() entirely. If you need the
|
|
354
|
+
server to generate synthetic samples for you to score first, use
|
|
355
|
+
synthesize_data() and train_surrogate() directly instead (see
|
|
356
|
+
examples/basic_usage.py).
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
data (str | Path | DataFrame): a CSV path, or an already-loaded DataFrame,
|
|
360
|
+
containing both the feature columns and target_col.
|
|
361
|
+
target_col (str): name of the column to train against.
|
|
362
|
+
feature_names (list): subset of feature columns to train on; omit for all.
|
|
363
|
+
(The full sample width is always uploaded — feature_names only tells
|
|
364
|
+
the surrogate which columns to actually fit on.)
|
|
365
|
+
task (str): specifies the modeling task, one of "classification," "regression," or "auto".
|
|
366
|
+
test_size (float): fraction of the data to set aside for test data, defaults to 0.2.
|
|
367
|
+
schema_name (str): name to store the inferred schema under.
|
|
368
|
+
immutable_cols (list): passed through to get_schema().
|
|
369
|
+
name (str): an optional name for the surrogate.
|
|
370
|
+
comments (str): an optional comment string for the surrogate.
|
|
371
|
+
Returns:
|
|
372
|
+
JSON object denoting surrogate training result, or None if schema upload
|
|
373
|
+
or training failed.
|
|
374
|
+
"""
|
|
375
|
+
df = data if isinstance(data, pd.DataFrame) else pd.read_csv(data)
|
|
376
|
+
target = df[target_col]
|
|
377
|
+
features_df = df.drop(columns=[target_col])
|
|
378
|
+
|
|
379
|
+
schema = get_schema(features_df, immutable_cols=immutable_cols)
|
|
380
|
+
if put_schema(schema, name=schema_name) is None:
|
|
381
|
+
return None
|
|
382
|
+
|
|
383
|
+
return train_surrogate(
|
|
384
|
+
samples=features_df.values.tolist(),
|
|
385
|
+
predictions=target.tolist(),
|
|
386
|
+
feature_names=feature_names,
|
|
387
|
+
task=task,
|
|
388
|
+
test_size=test_size,
|
|
389
|
+
schema_name=schema_name,
|
|
390
|
+
name=name,
|
|
391
|
+
comments=comments,
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def export_surrogate(version: str) -> SurrogateExport | None:
|
|
396
|
+
"""
|
|
397
|
+
Exports a surrogate model — classes, intercept, per_class_intercepts, features,
|
|
398
|
+
scalers, etc.; everything required to reconstruct the surrogate. Score it locally,
|
|
399
|
+
with zero sklearn, via proxyml_core.export.predict_from_export(export, sample).
|
|
400
|
+
|
|
331
401
|
Args:
|
|
332
402
|
version (str): name of the surrogate to export
|
|
333
403
|
Returns:
|
|
334
|
-
|
|
404
|
+
SurrogateExport, or None if an error occurred.
|
|
335
405
|
"""
|
|
336
406
|
r = get(endpoint=f'/surrogate/models/{version}/export', params=dict())
|
|
337
407
|
if r.status_code == 200:
|
|
338
|
-
return r.json()
|
|
339
|
-
logger.error(
|
|
340
|
-
"Surrogate export failed (version=%s, status=%s): %s",
|
|
341
|
-
version, r.status_code, r.text,
|
|
408
|
+
return SurrogateExport.from_dict(r.json())
|
|
409
|
+
logger.error(
|
|
410
|
+
"Surrogate export failed (version=%s, status=%s): %s",
|
|
411
|
+
version, r.status_code, r.text,
|
|
342
412
|
)
|
|
343
413
|
return None
|
|
344
414
|
|
|
@@ -560,18 +630,21 @@ def get_model_summary(version: str | None = None) -> Any:
|
|
|
560
630
|
return None
|
|
561
631
|
|
|
562
632
|
|
|
563
|
-
def get_model_schema(version: str) ->
|
|
633
|
+
def get_model_schema(version: str) -> FeatureSchema | None:
|
|
564
634
|
"""
|
|
565
635
|
Retrieves the schema associated with a particular surrogate.
|
|
566
|
-
|
|
636
|
+
|
|
567
637
|
Args:
|
|
568
638
|
version (str): name of the surrogate model.
|
|
569
639
|
Returns:
|
|
570
|
-
|
|
640
|
+
The model's FeatureSchema, or None if an error occurred.
|
|
571
641
|
"""
|
|
572
642
|
r = get(endpoint=f'/surrogate/models/{version}/schema', params=dict())
|
|
573
643
|
if r.status_code == 200:
|
|
574
|
-
|
|
644
|
+
payload = r.json()
|
|
645
|
+
if payload.get('schema_warning'):
|
|
646
|
+
logger.warning(payload['schema_warning'])
|
|
647
|
+
return FeatureSchema.from_dict(payload)
|
|
575
648
|
logger.error(
|
|
576
649
|
"Schema retrieval failed with status %s: %s",
|
|
577
650
|
r.status_code,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
try:
|
|
2
|
+
import proxyml_core.modeling # noqa: F401
|
|
3
|
+
except ImportError as exc:
|
|
4
|
+
raise ImportError(
|
|
5
|
+
"Local challenger training requires the 'local' extra: pip install 'proxyml[local]'"
|
|
6
|
+
) from exc
|
|
7
|
+
|
|
8
|
+
from proxyml.local.challenger import (
|
|
9
|
+
LADDERS,
|
|
10
|
+
Complexity,
|
|
11
|
+
Rung,
|
|
12
|
+
TrainedChallenger,
|
|
13
|
+
train_auto_challenger,
|
|
14
|
+
train_challenger,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"train_challenger",
|
|
19
|
+
"train_auto_challenger",
|
|
20
|
+
"Complexity",
|
|
21
|
+
"Rung",
|
|
22
|
+
"TrainedChallenger",
|
|
23
|
+
"LADDERS",
|
|
24
|
+
]
|