Skip to main content

Native LUT remapping for large Pandas categorical code buffers

Project description

zh_catmut

Python 3.9+ Native Core DataFrame License

Remap huge Pandas categorical columns without expanding them into object arrays or allocating boolean masks.

Before / After

# Before: high-level remapping can allocate temporary arrays or trigger
# categorical re-encoding work on the full column.
series = series.cat.rename_categories({"pending": "active"})
series = series.cat.set_categories(["active", "disabled"])

# After: build a dense metadata LUT, mutate integer categorical codes natively,
# and return a refreshed categorical object.
from zh_catmut import remap_categorical

series = remap_categorical(
    series,
    {"pending": "active", "disabled_old": "disabled"},
    copy_fallback=True,
)

Installation

For released wheels:

pip install zh-catmut

For a source checkout:

python -m pip install .

Verify the installed wheel and bundled native library:

zh-catmut doctor

The import package name uses an underscore:

import zh_catmut

Quickstart

import pandas as pd
from zh_catmut import remap_categorical

s = pd.Series(pd.Categorical(["new", "old", "old", None]))
out = remap_categorical(s, {"old": "new"}, copy_fallback=True)

copy_fallback=True is the safest default for application code because it allocates a Python-owned destination codes buffer and keeps the original object unchanged.

Why it's fast

  • Pandas categoricals store the full column as dense integer codes; category labels are only metadata.
  • zh_catmut builds a small dense int64 lookup table from category labels in Python.
  • A bundled Zig shared library receives only raw pointers, lengths, primitive flags, and POD reports through a C ABI.
  • The native loop remaps contiguous int8, int16, int32, or int64 code buffers in one batch.
  • ctypes.CDLL is used so the GIL is released while the native remap executes.
  • Python runs shape, dtype, contiguity, writeability, and Copy-on-Write safety gates before exporting pointers.
  • Native validation is all-or-nothing: invalid source codes, invalid target codes, null pointers, and oversized lengths are rejected before mutation.
  • If in-place mutation is unsafe, copy_fallback=True uses a Python-owned destination buffer and keeps the source buffer unchanged.

Public API

from zh_catmut import remap_categorical, remap_codes_inplace

Use remap_categorical for Pandas objects and remap_codes_inplace only when you already own a writable, contiguous NumPy codes buffer and a dense int64 LUT.

remap_categorical

remap_categorical(
    obj,
    mapping,
    *,
    assume_unique=False,
    copy_fallback=False,
    threads=0,
)
  • obj: a Pandas Series with categorical dtype or a pd.Categorical.
  • mapping: mapping from old labels to new labels. Labels not present in the mapping are preserved.
  • copy_fallback: when True, allocate a destination codes buffer and avoid in-place ownership risk.
  • assume_unique: expert-only escape hatch for controlled in-place mutation after all other gates pass.
  • threads: reserved for future native parallelism. The current V1 kernel accepts 0 or 1 and uses the scalar remap path.

remap_codes_inplace

remap_codes_inplace(
    codes,
    lut,
    *,
    target_category_count,
    missing_code=-1,
    allow_missing=True,
    threads=0,
)
  • codes: one-dimensional, C-contiguous NumPy array with dtype int8, int16, int32, or int64.
  • lut: one-dimensional, C-contiguous np.int64 lookup table.
  • target_category_count: every mapped non-missing code must be in [0, target_category_count).
  • missing_code: default -1, matching Pandas categorical codes.
  • allow_missing: when False, missing input or missing LUT output is rejected before mutation.

Command-line help for installed users

zh-catmut installs a small diagnostic CLI:

zh-catmut --help
zh-catmut info
zh-catmut example
zh-catmut doctor
python -m zh_catmut doctor
  • info prints the project purpose, install command, API summary, and support links.
  • example prints a minimal copy_fallback=True Pandas example.
  • doctor verifies NumPy/Pandas imports, native library loading, ABI version, and low/high-level remap smoke tests.
  • If your Python user scripts directory is not on PATH, use python -m zh_catmut ... instead of zh-catmut ....

Testing and native transparency

The native implementation is tracked in native/src/root.zig, with the C ABI declared in include/zh_catmut_abi.h. Tests are included so the compiled shared library is not a black-box artifact:

python -m pip install -e ".[test]"
python -m pytest -q
cd native && zig build test

The Python tests load the packaged native library, verify the ABI, exercise every supported integer code dtype, check all-or-nothing validation, run the Pandas copy-fallback path, and execute python -m zh_catmut doctor.

Troubleshooting

NativeLibraryLoadError

Run:

zh-catmut doctor

If the package was installed from a wheel, reinstall:

python -m pip install --force-reinstall zh-catmut

If pip built from source, Zig must be installed and visible as zig on PATH, or set:

ZIG=/path/to/zig python -m pip install zh-catmut

Copy-on-Write safety errors

For ordinary Pandas application code, prefer:

out = remap_categorical(series, mapping, copy_fallback=True)

Use assume_unique=True only when you control the object lifetime and know the underlying categorical codes buffer is not shared.

Supported runtime inputs

  • Python 3.9+
  • CPython
  • NumPy + Pandas
  • Pandas categorical codes backed by contiguous signed integer arrays
  • Code dtypes: int8, int16, int32, int64

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zh_catmut-0.1.0.tar.gz (23.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zh_catmut-0.1.0-cp39-cp39-macosx_11_0_arm64.whl (20.7 kB view details)

Uploaded CPython 3.9macOS 11.0+ ARM64

File details

Details for the file zh_catmut-0.1.0.tar.gz.

File metadata

  • Download URL: zh_catmut-0.1.0.tar.gz
  • Upload date:
  • Size: 23.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for zh_catmut-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0255a02cb7e8041fb38c5bdc2338a392bd8d7a04548bf4b771e3730ab484fa3a
MD5 d8f81562d34fe9c02e252b1cf209c367
BLAKE2b-256 283f677ee473b5b83fec885a69352c32c27839f7716ef6d1b6edce325483b192

See more details on using hashes here.

File details

Details for the file zh_catmut-0.1.0-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for zh_catmut-0.1.0-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5fb5a0a8fd85815f6b8f672207a8230fdfc17150e9c48d146949530ba8dd6f6c
MD5 6f4ae80e596f277bbbf84b28a4d58dff
BLAKE2b-256 88de4f186a041bfaea90bee5dd4ca0e48dff90123754d09a4d302dfb6e78fb50

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page