Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Please share your story by answering 1 quick question
* ArcSinhTransformer

### Variable Scaling methods
* MeanNormalizationScaler
* MeanNormalisationScaler

### Variable Creation:
* MathFeatures
Expand Down
6 changes: 6 additions & 0 deletions docs/api_doc/scaling/MeanNormalisationScaler.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
MeanNormalisationScaler
=======================

.. autoclass:: feature_engine.scaling.MeanNormalisationScaler
:members:

6 changes: 0 additions & 6 deletions docs/api_doc/scaling/MeanNormalizationScaler.rst

This file was deleted.

2 changes: 1 addition & 1 deletion docs/api_doc/scaling/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ given columns.
.. toctree::
:maxdepth: 1

MeanNormalizationScaler
MeanNormalisationScaler
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ procedures to a subset of the variables only, check out the :doc:`api_doc/wrappe

Feature-engine extends scikit-learn's scaling functionality with the following transformer:

- :doc:`api_doc/scaling/MeanNormalizationScaler`: scale variables using mean normalisation
- :doc:`api_doc/scaling/MeanNormalisationScaler`: scale variables using mean normalisation


Scikit-learn Wrapper:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

.. currentmodule:: feature_engine.scaling

MeanNormalizationScaler
MeanNormalisationScaler
=======================

.. attention::

**New in version 2.0:** When `variables` is `None`, :class:`MeanNormalizationScaler()` used to
**New in version 2.0:** When `variables` is `None`, :class:`MeanNormalisationScaler()` used to
raise an error if the dataframe contained no numerical variables. You can now
set the new parameter `return_empty` to `True` to make the transformer return an
empty list of variables and skip the scaling instead, leaving the dataframe
Expand All @@ -28,23 +28,23 @@ Mean normalisation is given by the following formula:

X' = (X - Mean(X)) / (Max(X) - Min(X))

:class:`MeanNormalizationScaler()` scales variables using mean normalisation.
:class:`MeanNormalisationScaler()` scales variables using mean normalisation.

.. note::

:class:`MeanNormalizationScaler()` only works with non-constant numerical variables.
:class:`MeanNormalisationScaler()` only works with non-constant numerical variables.
If the variable is constant, the scaler will raise an error.

Python implementation
---------------------

We'll show how to use :class:`MeanNormalizationScaler()` through a toy dataset. Let's create
We'll show how to use :class:`MeanNormalisationScaler()` through a toy dataset. Let's create
a toy dataset:

.. code:: python

import pandas as pd
from feature_engine.scaling import MeanNormalizationScaler
from feature_engine.scaling import MeanNormalisationScaler

df = pd.DataFrame.from_dict(
{
Expand Down Expand Up @@ -81,12 +81,12 @@ First, let's make a list with the variable names:
'Height',
]

Now, let's set up :class:`MeanNormalizationScaler()`:
Now, let's set up :class:`MeanNormalisationScaler()`:

.. code:: python

# set up the scaler
scaler = MeanNormalizationScaler(variables = vars)
scaler = MeanNormalisationScaler(variables = vars)

# fit the scaler
scaler.fit(df)
Expand Down Expand Up @@ -155,4 +155,4 @@ For tutorials about this and other feature engineering methods check out these r

Both our book and courses are suitable for beginners and more advanced data scientists
alike. By purchasing them you are supporting `Sole <https://linkedin.com/in/soledad-galli>`_,
the main developer of feature-engine.
the main developer of feature-engine.
2 changes: 1 addition & 1 deletion docs/user_guide/scaling/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ Scalers
.. toctree::
:maxdepth: 1

MeanNormalizationScaler
MeanNormalisationScaler
3 changes: 2 additions & 1 deletion feature_engine/scaling/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
scaling methods.
"""

from .mean_normalization import MeanNormalizationScaler
from .mean_normalization import MeanNormalisationScaler, MeanNormalizationScaler

__all__ = [
"MeanNormalisationScaler",
"MeanNormalizationScaler",
]
28 changes: 23 additions & 5 deletions feature_engine/scaling/mean_normalization.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Authors: Vasco Schiavo <vasco.schiavo@protonmail.com>
# License: BSD 3 clause

import warnings
from typing import List, Optional, Union

import pandas as pd
Expand Down Expand Up @@ -37,9 +38,9 @@
fit_transform=_fit_transform_docstring,
inverse_transform=_inverse_transform_docstring,
)
class MeanNormalizationScaler(BaseNumericalTransformer):
class MeanNormalisationScaler(BaseNumericalTransformer):
"""
MeanNormalizationScaler() applies mean normalisation, which consists of subtracting
MeanNormalisationScaler() applies mean normalisation, which consists of subtracting
the mean of each feature and then dividing the result by the value range, that is,
the difference between its maximum and minimum value. The method aims to center the
variables at 0, and rescale the distribution between -1 and 1.
Expand All @@ -51,7 +52,6 @@ class MeanNormalizationScaler(BaseNumericalTransformer):

More details in the :ref:`User Guide <mean_normalisation_scaler>`.


Parameters
----------
{variables}
Expand Down Expand Up @@ -89,10 +89,10 @@ class MeanNormalizationScaler(BaseNumericalTransformer):

>>> import numpy as np
>>> import pandas as pd
>>> from feature_engine.scaling import MeanNormalizationScaler
>>> from feature_engine.scaling import MeanNormalisationScaler
>>> np.random.seed(42)
>>> X = pd.DataFrame(dict(x = np.random.lognormal(size = 100)))
>>> mns = MeanNormalizationScaler()
>>> mns = MeanNormalisationScaler()
>>> mns.fit(X)
>>> X = mns.transform(X)
>>> X.head()
Expand Down Expand Up @@ -189,3 +189,21 @@ def inverse_transform(self, X: pd.DataFrame) -> pd.DataFrame:
X[self.variables_] = X[self.variables_] * self.range_ + self.mean_

return X


Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# TODO: remove in version 2.1.0

# TODO: remove in version 2.1.0
class MeanNormalizationScaler(MeanNormalisationScaler):
def __init__(
self,
variables: Union[None, int, str, List[Union[str, int]]] = None,
return_empty: bool = False,
) -> None:
warnings.warn(
"MeanNormalizationScaler was deprecated in favour of "
"MeanNormalisationScaler in version 2.0.0 and will be removed in "
"version 2.1.0. To silence this warning, use MeanNormalisationScaler "
"instead.",
FutureWarning,
stacklevel=2,
)
super().__init__(variables=variables, return_empty=return_empty)
67 changes: 50 additions & 17 deletions tests/test_scaling/test_mean_normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,37 @@
import pytest
from sklearn.exceptions import NotFittedError

from feature_engine.scaling import MeanNormalizationScaler
from feature_engine.scaling import MeanNormalisationScaler, MeanNormalizationScaler
from tests.estimator_checks.fit_functionality_checks import check_return_empty

DEPRECATION_WARNING = (
"MeanNormalizationScaler was deprecated in favour of "
"MeanNormalisationScaler in version 2.0.0 and will be removed in version 2.1.0. "
"To silence this warning, use MeanNormalisationScaler instead."
)

def test_transforming_int_vars():

@pytest.fixture(
params=[MeanNormalisationScaler, MeanNormalizationScaler],
ids=["MeanNormalisationScaler", "MeanNormalizationScaler"],
)
def transformer_class(request):
return request.param


def make_transformer(transformer_class, **kwargs):
if transformer_class is MeanNormalizationScaler:
with pytest.warns(FutureWarning, match=re.escape(DEPRECATION_WARNING)):
return transformer_class(**kwargs)
return transformer_class(**kwargs)


def test_mean_normalization_scaler_raises_future_warning():
with pytest.warns(FutureWarning, match=re.escape(DEPRECATION_WARNING)):
MeanNormalizationScaler()


def test_transforming_int_vars(transformer_class):
# input test case
df = pd.DataFrame(
{
Expand All @@ -26,7 +52,7 @@ def test_transforming_int_vars():
}
)

transformer = MeanNormalizationScaler(variables=None)
transformer = make_transformer(transformer_class, variables=None)
X = transformer.fit_transform(df)

pd.testing.assert_frame_equal(X, expected_df)
Expand All @@ -37,9 +63,11 @@ def test_transforming_int_vars():
pd.testing.assert_frame_equal(Xit, df)


def test_mean_normalization_plus_automatically_find_variables(df_vartypes):
def test_mean_normalization_plus_automatically_find_variables(
df_vartypes, transformer_class
):
# test case 1: automatically select variables
transformer = MeanNormalizationScaler(variables=None)
transformer = make_transformer(transformer_class, variables=None)
X = transformer.fit_transform(df_vartypes)

# expected output
Expand All @@ -66,9 +94,9 @@ def test_mean_normalization_plus_automatically_find_variables(df_vartypes):
pd.testing.assert_frame_equal(Xit, df_vartypes, rtol=10e-3)


def test_mean_normalization_plus_user_passes_var_list(df_vartypes):
def test_mean_normalization_plus_user_passes_var_list(df_vartypes, transformer_class):
# test case 2: user passes variables
transformer = MeanNormalizationScaler(variables="Age")
transformer = make_transformer(transformer_class, variables="Age")
X = transformer.fit_transform(df_vartypes)

# expected output
Expand All @@ -93,28 +121,28 @@ def test_mean_normalization_plus_user_passes_var_list(df_vartypes):
pd.testing.assert_frame_equal(Xit, df_vartypes, rtol=10e-3)


def test_fit_raises_error_if_na_in_df(df_na):
def test_fit_raises_error_if_na_in_df(df_na, transformer_class):
# test case 3: when dataset contains na, fit method
transformer = MeanNormalizationScaler()
transformer = make_transformer(transformer_class)
with pytest.raises(ValueError):
transformer.fit(df_na)


def test_transform_raises_error_if_na_in_df(df_vartypes, df_na):
def test_transform_raises_error_if_na_in_df(df_vartypes, df_na, transformer_class):
# test case 4: when dataset contains na, transform method
transformer = MeanNormalizationScaler()
transformer = make_transformer(transformer_class)
transformer.fit(df_vartypes)
with pytest.raises(ValueError):
transformer.transform(df_na[["Name", "City", "Age", "Marks", "dob"]])


def test_non_fitted_error(df_vartypes):
transformer = MeanNormalizationScaler()
def test_non_fitted_error(df_vartypes, transformer_class):
transformer = make_transformer(transformer_class)
with pytest.raises(NotFittedError):
transformer.transform(df_vartypes)


def test_constant_columns_error():
def test_constant_columns_error(transformer_class):
# input test case
df = pd.DataFrame(
{
Expand All @@ -124,10 +152,15 @@ def test_constant_columns_error():
}
)

transformer = MeanNormalizationScaler()
transformer = make_transformer(transformer_class)
with pytest.raises(ValueError, match=re.escape("Division by zero is not allowed")):
transformer.fit(df)


def test_check_return_empty():
check_return_empty(MeanNormalizationScaler())
def test_check_return_empty(transformer_class):
transformer = make_transformer(transformer_class)
if transformer_class is MeanNormalizationScaler:
with pytest.warns(FutureWarning, match=re.escape(DEPRECATION_WARNING)):
check_return_empty(transformer)
else:
check_return_empty(transformer)