chc.frames¶
Stability tier: evolving.
Accept a columnar frame -- pandas, polars, or a plain mapping -- wherever chc takes named data.
Neither pandas nor polars is a chc dependency, so a frame is recognised structurally rather than
by import: both expose .columns and frame[name], and every column converts through
np.asarray. Estimators call as_columns once on entry and index a plain dict afterwards.
The mapping branch is guarded by an isinstance rather than by duck-typing, because a frame that
is not a Mapping still survives the mapping idioms with the wrong answer instead of an error:
dict(polars_frame) and for name in polars_frame both iterate columns as values, handing a
caller column data where it asked for column names.
A column read as numbers holds real numbers. NumPy's cast to float64 takes far more: it reads the
text "1.5" as 1.5, a date as its count of days since 1970, and a Decimal of 1E+400 as
an infinity. So a reader of numbers reads a caller's column through one check, which refuses
text, dates, times, durations, complex numbers and any other object that is not a real number,
and a real number that is finite but past float64's range, naming the column and the row. An entry
point that takes a caller's data as arrays, not as named columns, reads each through the same
check as it enters (_real_numbers), naming the argument.
ColumnData = Mapping[str, Any] | ColumnFrame
module-attribute
¶
What every chc entry point that takes named data accepts.
ColumnFrame
¶
Bases: Protocol
A frame with named columns, indexable by name: pandas, polars, pyarrow, and friends.
as_columns(data)
¶
Normalise data to {name: column} from a mapping or any columnar frame.
The values are Any rather than ArrayLike and that is the honest type, not a shortcut: a
mapping's columns come back exactly as they went in, so their type is the caller's, and every
consumer here re-asserts it with the asarray its own precision contract requires.
A mapping passes through unconverted, which is what keeps this cheap enough to sit on every
entry point: the library's own callers hand over JAX arrays, and np.asarray on those would
force a device-to-host copy and raise outright on a tracer inside jax.jit. Only the frame
branch materialises, and it stops at NumPy -- precision is the caller's decision, and the two
consumers disagree on purpose (chc.gmethods is float64 by contract, the estimators follow
JAX's x64 flag).
A NumPy masked array is read through its mask, in either branch. A masked cell is a missing value, and no reader of named columns here takes one --- a panel refuses a nan, and a fit would read what lies under the mask as data --- so a column with one is refused. A masked array that masks no cell is its data.
Raises:
| Type | Description |
|---|---|
TypeError
|
when |
ValueError
|
when two columns go by one name as text -- |