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
5 changes: 0 additions & 5 deletions feature_engine/encoding/count_frequency.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,6 @@ def fit(self, X: IntoDataFrame, y: Optional[IntoSeries] = None):
variables_ = self._check_or_select_variables(X)
self._check_na(X, variables_)

if self.encoding_method not in ["count", "frequency"]:
raise ValueError(
"Unrecognized value for encoding_method. It should be 'count' or "
f"'frequency'. Got {self.encoding_method} instead."
)
normalize = self.encoding_method == "frequency"

self.encoder_dict_ = {}
Expand Down
38 changes: 38 additions & 0 deletions tests/backend_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Helpers for tests that run on several dataframe backends.
Use them together with the `make_df` fixture in `tests/conftest.py`.
"""

import narwhals as nw
import pandas as pd
import polars as pl


def frame_to_dict(X):
"""Return the dataframe contents as ``{column: list of values}``.

pandas represents missing values as NaN and polars as None, so NaN (and
pd.NA) are normalised to None and the same expected values work for both
backends.
"""
result = nw.from_native(X, eager_only=True).to_dict(as_series=False)
return {
col: [none_if_missing(v) for v in values] for col, values in result.items()
}


def null_count(X, col):
"""Return the number of missing values in column ``col``."""
return nw.from_native(X, eager_only=True).get_column(col).null_count()


def make_series(make_df, values, name=None):
"""Build a Series on the same backend as ``make_df``."""
if make_df is pd.DataFrame:
return pd.Series(values, name=name)
return pl.Series(name=name or "", values=values)


def none_if_missing(value):
if value is pd.NA or (isinstance(value, float) and value != value):
return None
return value
11 changes: 11 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import numpy as np
import pandas as pd
import polars as pl
import pytest


@pytest.fixture(params=[pd.DataFrame, pl.DataFrame], ids=["pandas", "polars"])
def make_df(request):
"""Dataframe constructor of the backend under test: pandas or polars.

A test that requests this fixture runs once per backend. Build the input
with ``make_df(data)`` and check the output with ``isinstance(X, make_df)``.
"""
return request.param


@pytest.fixture(scope="module")
def df_vartypes():
data = {
Expand Down
111 changes: 111 additions & 0 deletions tests/test_encoding/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""Data shared by the encoder tests.

Each fixture returns a fresh dict, so tests can build the dataframe on the
backend under test with `make_df(data)`. Missing values are written as None,
which both pandas and polars read as missing.
"""

import pytest

TARGET = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0]


@pytest.fixture
def data_enc():
return {
"var_A": ["A"] * 6 + ["B"] * 10 + ["C"] * 4,
"var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4,
"target": list(TARGET),
}


@pytest.fixture
def data_enc_rare():
return {
"var_A": ["B"] * 9 + ["A"] * 6 + ["C"] * 4 + ["D"] * 1,
"var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4,
"target": list(TARGET),
}


@pytest.fixture
def data_enc_na():
return {
"var_A": [None] + ["B"] * 8 + ["A"] * 6 + ["C"] * 4 + ["D"] * 1,
"var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4,
"target": list(TARGET),
}


@pytest.fixture
def data_enc_numeric():
return {
"var_A": [1] * 6 + [2] * 10 + [3] * 4,
"var_B": [1] * 10 + [2] * 6 + [3] * 4,
"target": list(TARGET),
}


def _data_enc_big():
return {
"var_A": ["A"] * 6
+ ["B"] * 10
+ ["C"] * 4
+ ["D"] * 10
+ ["E"] * 2
+ ["F"] * 2
+ ["G"] * 6,
"var_B": ["A"] * 10
+ ["B"] * 6
+ ["C"] * 4
+ ["D"] * 10
+ ["E"] * 2
+ ["F"] * 2
+ ["G"] * 6,
"var_C": ["A"] * 4
+ ["B"] * 6
+ ["C"] * 10
+ ["D"] * 10
+ ["E"] * 2
+ ["F"] * 2
+ ["G"] * 6,
}


@pytest.fixture
def data_enc_big():
return _data_enc_big()


@pytest.fixture
def data_enc_big_na():
data = _data_enc_big()
data["var_A"][0] = None
return data


@pytest.fixture
def data_enc_top():
return {
"var_A": ["A"] * 5
+ ["B"] * 11
+ ["C"] * 4
+ ["D"] * 9
+ ["E"] * 2
+ ["F"] * 2
+ ["G"] * 7,
"var_B": ["A"] * 11
+ ["B"] * 7
+ ["C"] * 4
+ ["D"] * 9
+ ["E"] * 2
+ ["F"] * 2
+ ["G"] * 5,
"var_C": ["A"] * 4
+ ["B"] * 5
+ ["C"] * 11
+ ["D"] * 9
+ ["E"] * 2
+ ["F"] * 2
+ ["G"] * 7,
}
Loading