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, the human-readable level names shown on the plot axis instead of the numeric codes: a {level value: name} dict (levels absent from the data are fine), or a list with one name per observed level in ascending order; 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, return_encoding=False)
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 (a {code: name} dict per encoded column):
| 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
|
return_encoding
|
bool
|
also return the |
False
|
Returns:
| Type | Description |
|---|---|
|
|
|
|
is an |
|
|
|
|
|
when |
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
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | |
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.