Encoders: cache mappings/indexes in transform for fast small batches transform - #15
Open
cakedev0 wants to merge 3 commits into
Open
Encoders: cache mappings/indexes in transform for fast small batches transform#15cakedev0 wants to merge 3 commits into
cakedev0 wants to merge 3 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reference Issues/PRs
Based on top of scikit-learn#34678, that's why I open this on my fork for now.
Supersedes scikit-learn#32368 and #13
What does this implement/fix? Explain your changes.
Speeds up repeated small-batch
transformcalls (e.g. scoring one row at a time in a serving loop) forOneHotEncoder,OrdinalEncoderandTargetEncoder.To achieve that, I cache the mapping/index used by
_encodefor the two non-numerical paths (objects array, string/categorical Series). This mapping/index costs O(n_categories) to build, it's what makes this path particularly slow for small batches.The numerical path doesn't suffer from such an O(n_categories) cost, so it's left unchanged.
AI usage disclosure
moderate
Benchmarks
Using
benchmarks/bench_encoders.py, this branch vs its base (scikit-learn#34678),transform_single_msonly (repeated single-rowtransformcalls on an encoder). Measured withPYTHONHASHSEED=0(str hashing is randomized per-process by default, which is otherwise a real source of noise on thestring/objectcolumns).base | branch, in ms:No regressions anywhere in this matrix. The speed-up tracks category count (
n_categories), as expected since that's exactly the cost being amortized away: biggest onamazon_employee_access/kddcup09_churn(highest-cardinality columns), smallest onbank_marketing/house_prices(mostly very low-cardinality columns, where the O(n_categories) table-building cost was already small).Open question
This PR is a memory-performance trade-off case. In most cases, the memory cost is quite negligible (n_categories << n_rows) and when it's not, it's when the speed-up is the bigger (high n_categories). This is what makes me confident
Still, maybe the users should have the choice? We could imagine introducing a
cache_transform=False/Trueparameter to each impacted encoder. In that case, the transform cache could be initialized eagerly (instead of lazily) when the user opted forcache_transform=True.