Input layer — Schema & from_dataframe
Summary
effector is numpy-only at the border (design contract R10): data is a 2-D
numeric numpy array, the model is a numpy→numpy callable, and all input
metadata travels in the single schema= argument — an effector.Schema
(frozen dataclass, reusable across constructions) or a plain dict with the
same keys. Every field is optional; anything omitted is inferred
conservatively (nominal is never guessed from a numpy matrix).
schema = {
"feature_names": ["hr", "temp", "workingday"],
"feature_types": ["ordinal", "continuous", "nominal"],
"target_name": "count",
}
pdp = effector.PDP(X, model, schema=schema)
Coming from pandas, from_dataframe reads names, dtypes, and category levels
into (X, Schema) — it converts data only and never touches the model. The
returned schema is a proposal to inspect: the int-column guess (ordinal vs
continuous vs label-encoded nominal) is the one thing no extractor can know
for sure.
X, schema = effector.from_dataframe(df)
ale = effector.ALE(X, model, schema=schema)
(For the model side of the border — sklearn/torch/classifier wrappers — see Adapters.)
API
effector.ingestion.Schema(feature_names=None, feature_types=None, cat_limit=None, target_name=None, scale_x_list=None, scale_y=None, category_names=None)
dataclass
The single metadata argument of every effector constructor.
schema = effector.Schema(
feature_names=["hr", "temp", "workingday"],
feature_types=["ordinal", "continuous", "nominal"],
target_name="count",
)
pdp = effector.PDP(X, model, schema=schema)
Every field is optional: whatever you do not declare is inferred from the
numpy data (type heuristic) or synthesized (x_0…, "y"). A Schema
holds no data, so one instance can be reused across method constructions.
Constructors also accept a plain dict with the same keys.
| Field | Meaning |
|---|---|
feature_names |
one name per column (default x_0, x_1, …) |
feature_types |
"continuous" / "ordinal" / "nominal" per column (aliases: "cont" → continuous, "cat" → nominal) |
cat_limit |
cardinality threshold for the int-column type heuristic (default 10) |
target_name |
name of the model output (default "y") |
scale_x_list |
per-feature {"mean": .., "std": ..} dicts (or None entries) to display plots in original units; plot-time scale_x overrides |
scale_y |
{"mean": .., "std": ..} for the output axis; plot-time scale_y overrides |
category_names |
per categorical (ordinal/nominal) feature: one human-readable name per observed level in ascending order, shown on the plot axis instead of the numeric codes; None entries keep the codes |
Coming from pandas
effector.from_dataframe(df) populates a Schema from a DataFrame's
names/dtypes/levels — inspect the result, then pass it on.
effector.ingestion.from_dataframe(df, *, cat_limit=DEFAULT_CAT_LIMIT)
Extract a numpy matrix and a populated Schema from a pandas DataFrame — data only.
X, schema = effector.from_dataframe(df)
pdp = effector.PDP(X, model, schema=schema)
Constructors hard-reject a DataFrame as data (effector is numpy-only);
this is the opt-in door. It reads column names, maps dtypes to feature
types, encodes non-numeric columns to float codes, and records the level
labels in category_names:
| DataFrame dtype | feature type | encoded as |
|---|---|---|
| float | continuous | values as-is |
| int | ordinal if nunique < cat_limit, else continuous |
values as-is |
| bool | ordinal | False, True → 0.0, 1.0 |
Categorical, ordered |
ordinal | category codes |
Categorical, unordered |
nominal | category codes |
| object / string | nominal | codes of astype("category") |
| anything else | — | raises ValueError |
The schema is a proposal — inspect it
The int-column guess (ordinal vs continuous vs a label-encoded
nominal) is the one thing no extractor can know for sure; it also
fires a UserWarning. Override any field before passing the schema on.
Never touches the model
model must already be a numpy->numpy callable. If your model
consumes a DataFrame (e.g. an sklearn Pipeline), wrap it yourself —
see effector.adapters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
a pandas DataFrame with numeric / bool / categorical / string columns (no missing values). |
required | |
cat_limit
|
int
|
cardinality threshold for the int-column ordinal heuristic (default 10), recorded on the returned schema. |
DEFAULT_CAT_LIMIT
|
Returns:
| Type | Description |
|---|---|
|
|
|
|
is an |
|
|
|
Raises:
| Type | Description |
|---|---|
TypeError
|
|
ValueError
|
a column contains missing values (the error names the column — impute or drop first), or has an unsupported dtype. |
Source code in effector/ingestion.py
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | |
effector.ingestion.FeatureMetadata(feature_names, feature_types, cat_limit, target_name, scale_x_list=None, scale_y=None, category_names=None)
dataclass
Resolved input metadata — what every effect object stores as feature_metadata.
pdp.feature_metadata.feature_names # ['hr', 'temp', 'workingday']
pdp.feature_metadata.feature_types # ['ordinal', 'continuous', 'nominal']
The read-only result of ingestion: Schema fields merged with inference,
every gap filled. You never construct one — read it off a fitted object.
Fields mirror Schema, except everything is resolved: types are canonical
strings and category_names is a {feature_idx: {level_value: name}} map.