Library / SDK
feature-engine/feature_engine avatar
feature-engine/feature_engine

Feature-engine: sklearn-compatible transformers for imputation, encoding and selection

Feature engineering and selection open-source Python library compatible with sklearn.

2,280 stars370 forksPythonBSD-3-Clause

At a glance

What is it?
Feature-engine packages feature engineering steps as scikit-learn style transformers with fit() and transform() methods. The value is in the breadth of the catalogue and the pipeline compatibility; the cost is a large API surface and a release history that is not uniform.
Who is it for?
Feature-engine is for teams already committed to scikit-learn pipelines who want imputation, encoding, discretisation, outlier handling and selection available as transformers rather than as ad hoc pandas code. It is the wrong tool if you need a small, auditable dependency or if your feature logic cannot be expressed as fit/transform.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap Feature-engine fills between pandas code and a fitted pipeline

Feature engineering in Python often starts as a notebook of pandas operations: fill missing values with the median, group rare categories, cap outliers at a percentile, drop correlated columns. That code works once. It becomes a problem when the same transformations have to be applied to training data and to new data at prediction time, because the parameters learned from the training set (the median, the percentile, the list of rare labels) have to be stored and reapplied.

Feature-engine's answer is to express each of those operations as a transformer that follows scikit-learn's interface. The README states that its transformers "follow Scikit-learn's functionality with fit() and transform() methods to learn the transforming parameters from the data and then transform it." That is the whole pitch: the learned state lives in the object, so the object can be placed in a Pipeline and serialised alongside the model.

The intended audience is therefore narrow but well defined. It is for people who already build models with scikit-learn and who want feature preparation to be part of the fitted object rather than a separate script. It is not a general data-wrangling library, and it does not replace pandas for exploratory work.

What is actually in the transformer catalogue

The README lists the categories and the class names in each. Imputation covers MeanMedianImputer, ArbitraryImputer, RandomSampleImputer, EndTailImputer, CategoricalImputer, MissingIndicator and DropMissingData. Encoding covers OneHotEncoder, OrdinalEncoder, CountEncoder, MeanEncoder, WoEEncoder, RareLabelEncoder, DecisionTreeEncoder and StringSimilarityEncoder. Discretisation has EqualFrequencyDiscretiser, EqualWidthDiscretiser, GeometricWidthDiscretiser, DecisionTreeDiscretiser and ArbitraryDiscreriser. Outlier handling has Winsoriser, ArbitraryOutlierCapper and OutlierTrimmer.

Beyond those, the list continues with variable transformation (LogTransformer, ReciprocalTransformer, ArcsinTransformer, PowerTransformer, BoxCoxTransformer, YeoJohnsonTransformer, ArcSinhTransformer), scaling (MeanNormalisationScaler), variable creation (MathFeatures, RelativeFeatures, CyclicalFeatures, DecisionTreeFeatures, GeoDistanceFeatures) and feature selection (DropFeatures, DropConstantFeatures, DropDuplicateFeatures, DropCorrelatedFeatures, SmartCorrelationSelection, ShuffleFeaturesSelector, SelectBySingleFeaturePerformance, SelectByTargetEncoding, RecursiveFeatureElimination and RecursiveFeatureAd).

The selection group is where the library is most opinionated. DropCorrelatedFeatures and SmartCorrelationSelection both target redundancy, but they differ in what they do about it: dropping correlated columns outright versus selecting a subset. RecursiveFeatureElimination and RecursiveFeatureAd sit at opposite ends of the same idea, removing features or adding them. Note that the README list is the project's own summary, not a guarantee that every name is present in the version you install.

The fit and transform contract, and what it implies about data flow

The mechanism is the standard scikit-learn one. A transformer is instantiated with configuration, fit() is called on training data to learn parameters, and transform() applies those parameters. Because the parameters are learned rather than hard-coded, the same object can be reused on a held-out set or on production rows.

The practical consequence is that the data flow becomes explicit. Instead of a function that reads a dataframe and returns a dataframe, you get an object whose learned attributes can be inspected after fitting. That matters for review: a median imputation value or a list of rare labels is a decision that someone may need to justify, and keeping it inside the transformer makes it retrievable rather than buried in a notebook cell.

It also imposes a constraint. Anything that cannot be expressed as a learned parameter plus a deterministic transform does not fit the model. A feature that depends on a join to an external table, on a manual business rule, or on information that is only available after the prediction moment has to live outside the transformer chain. Feature-engine does not remove that boundary; it just moves it.

The README also mentions a group of scikit-learn wrappers, which suggests the project is aware that some transformations need to be adapted to fit the estimator interface rather than written from scratch. Beyond the category name, the README does not describe what those wrappers do.

Installing and wiring a transformer into a pipeline

The README points to PyPI and conda-forge as the distribution channels, via the PyPI and Conda badges. The package name on PyPI is feature-engine and the import name is feature_engine. Installation is therefore a standard pip or conda install of feature-engine, and the documentation at feature-engine.trainindata.com is the place to look for the exact class signatures, since the README lists class names without their parameters.

What the material does support is the shape of usage. You import a transformer from the feature_engine namespace, instantiate it, call fit() on the training dataframe, then transform(). The README's own framing is that parameters are learned during fit and applied during transform, so the configuration keys are constructor arguments rather than a separate config file. There is no config file, no CLI and no YAML in the material provided.

Because the transformers are scikit-learn compatible, the intended composition is a scikit-learn Pipeline. That is the integration point to test first: whether a given transformer's output column set matches what the next step expects. Column naming and ordering after transform are the usual source of friction in this style of library, and the README does not address them.

Where the API surface becomes the limitation

The most visible risk is size. The README lists well over forty transformer classes across thirteen categories. That is a lot of surface to keep consistent, and it means two things for an adopter.

First, the release history is not uniform. The recent releases shown are v1.9.4 dated 2026-07-21, then v1.2.0 dated 2022-01-04 and v1.1.2 dated 2021-09-18. The gap between the 1.1 and 1.2 releases and the later 1.9.4 line is wide, and the version numbering jumps from 1.2.0 to 1.9.4 across the listed entries. That does not prove anything about stability on its own, but it does mean you should not assume every transformer in the README list has been maintained at the same cadence. Pin a version and test the specific classes you use.

Second, breadth invites overlap. Several imputers, several encoders and several correlation-based selectors cover adjacent ground. Choosing between MeanEncoder and WoEEncoder, or between DropCorrelatedFeatures and SmartCorrelationSelection, requires reading the documentation rather than the README, because the README gives names and no decision guidance.

A third limitation is inherent to the approach. A transformer that learns from the training fold must be refit inside cross-validation, otherwise the learned parameters leak. Feature-engine does not change that; it just makes the leak easier to commit silently if you fit once outside the CV loop and reuse the object.

Feature-engine against scikit-learn's own preprocessing and against writing it yourself

The obvious comparison is scikit-learn's preprocessing module. The difference in approach is coverage and granularity. Scikit-learn's preprocessing centres on a smaller set of general-purpose transformers, with a well-known one-hot encoder, scalers and a simple imputer. Feature-engine's catalogue is organised around specific feature engineering decisions: rare label grouping, weight-of-evidence encoding, decision-tree-based discretisation, tail-based imputation, correlation-aware selection. Those are operations you would otherwise write by hand.

The second alternative is writing the transformations yourself as small scikit-learn compatible classes. That gives you exactly the behaviour you need and no dependency you did not choose. The cost is that you own the edge cases: unseen categories at transform time, all-null columns, constant columns, dtype changes. Feature-engine's value proposition is that those cases are someone else's problem, and the README's category list is essentially an inventory of the cases the project has chosen to handle.

A third route is a general-purpose feature engineering framework with a different execution model, such as a declarative or dataframe-agnostic pipeline. Those tend to trade the fit/transform object model for a specification you write once and execute against multiple backends. If your team already lives in scikit-learn, that trade is usually not worth making. If your feature logic is shared across several runtimes, it may be.

Licence, maintenance and upgrade cost

Feature-engine is released under BSD-3-Clause, per the repository metadata and the licence badge. That is a permissive licence: it allows use, modification and redistribution, including in closed-source products, provided the copyright notice and licence text are retained. It does not carry the copyleft obligations of a GPL-style licence, and it does not include an explicit patent grant of the kind found in Apache-2.0. This is a description of the licence text, not legal advice; if your organisation has a licence policy, run it past whoever owns that policy.

The maintenance picture from the supplied material is mixed. The repository is not archived, the last push is dated 2026-08-30, and the most recent release listed is v1.9.4 from 2026-07-21, so there is active work. But the release list also shows a long quiet period between the 2021 and 2022 releases and the 1.9.4 line, and the README's own framing of the project is tied to a commercial training business, TrainInData, which is listed as a sponsor and as the source of several courses and books built on the library. That is not a problem in itself, but it is context for how the project is funded and prioritised.

Upgrade cost is the practical concern. With a catalogue this wide, a minor version bump can change behaviour in a transformer you depend on. The mitigation is the same as for any scikit-learn extension: pin the version, keep a test that asserts the transformed output shape and column names for the transformers in your pipeline, and read the release notes before moving the pin.

Editorial conclusion

Feature-engine is for teams already committed to scikit-learn pipelines who want imputation, encoding, discretisation, outlier handling and selection available as transformers rather than as ad hoc pandas code. It is the wrong tool if you need a small, auditable dependency or if your feature logic cannot be expressed as fit/transform. Before adopting, verify three things in your own environment: that the transformer you need is in the current release rather than only in the README list, that its transform output feeds the downstream estimator you use, and that the version you pin is the one you tested.

Official sources

  1. feature-engine/feature_engine on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Community notes

Community notes