Repository: feature-engine/feature_engine (python)

Issue:
MatchVariables.transform returns error KeyError: "['City'] not in index"
**Describe the bug**
A clear and concise description of what the bug is.
When running the example found in `MatchVariables` I get a `KeyError: "['City'] not in index"`.

**To Reproduce**
Steps to reproduce the behavior:
Run this example

```python
import pandas as pd
import numpy as np
from feature_engine.imputation import DropMissingData
from feature_engine.preprocessing import MatchVariables

train = pd.DataFrame(
    {
        "Name": ["tom", "nick", "krish", "jack"],
        "City": ["London", "Manchester", "Liverpool", "Bristol"],
        "Age": [20, 21, 19, 18],
        "Marks": [0.9, 0.8, 0.7, 0.6],
    }
)

test = pd.DataFrame(
    {
        "Name": ["tom", "sam", "nick"],
        "Age": [20, 22, 23],
        "Marks": [0.9, 0.7, 0.6],
        "Hobbies": ["tennis", "rugby", "football"],
    }
)

match_columns = MatchVariables()

match_columns.fit(train)

df_transformed = match_columns.transform(test)
```

**Expected behavior**
A clear and concise description of what you expected to happen.
From the example here, it should return
```
        df_transformed

            Name    City  Age  Marks
        0    tom  np.nan   20    0.9
        1    sam  np.nan   22    0.7
        2   nick  np.nan   23    0.6
```

Pandas Version: 2.2.2



Pull request:
fix bug matchvariables
closes #789 

Patch:
diff --git a/feature_engine/preprocessing/match_columns.py b/feature_engine/preprocessing/match_columns.py
index 1b6099b..b39f5e0 100644
--- a/feature_engine/preprocessing/match_columns.py
+++ b/feature_engine/preprocessing/match_columns.py
@@ -63,9 +63,9 @@ class MatchVariables(BaseEstimator, TransformerMixin, GetFeatureNamesOutMixin):
     fill_value: integer, float or string. Default=np.nan
         The values for the variables that will be added to the transformed dataset.
 
-    missing_values: string, default='ignore'
+    missing_values: string, default='raise'
         Indicates if missing values should be ignored or raised. If 'raise' the
-        transformer will return an error if the the datasets to `fit` or `transform`
+        transformer will return an error if the datasets to `fit` or `transform`
         contain missing values. If 'ignore', missing data will be ignored when learning
         parameters or performing the transformation.
 
@@ -239,8 +239,11 @@ class MatchVariables(BaseEstimator, TransformerMixin, GetFeatureNamesOutMixin):
         X = check_X(X)
 
         if self.missing_values == "raise":
-            # check if dataset contains na
-            _check_contains_na(X, self.feature_names_in_)
+            # Some variables from the train set may not be present in the test set
+            # and vice versa. We'll check for nan only in the variables seen during
+            # training.
+            vars = [var for var in self.feature_names_in_ if var in X.columns]
+            _check_contains_na(X, vars)
 
         _columns_to_drop = list(set(X.columns) - set(self.feature_names_in_))
         _columns_to_add = list(set(self.feature_names_in_) - set(X.columns))


Test patch:
diff --git a/tests/test_preprocessing/test_match_columns.py b/tests/test_preprocessing/test_match_columns.py
index d0ec210..16ee063 100644
--- a/tests/test_preprocessing/test_match_columns.py
+++ b/tests/test_preprocessing/test_match_columns.py
@@ -325,3 +325,42 @@ def test_non_fitted_error(df_vartypes):
     with pytest.raises(NotFittedError):
         transformer = MatchVariables()
         transformer.transform(df_vartypes)
+
+
+def test_check_for_na_in_transform_does_not_fail():
+    # some variables seen during train may not be present in the test set, so we
+    # need to skip these ones during the check for na.
+    # Bug reported in https://github.com/feature-engine/feature_engine/issues/789
+    train = pd.DataFrame(
+        {
+            "Name": ["tom", "nick", "krish", "jack"],
+            "City": ["London", "Manchester", "Liverpool", "Bristol"],
+            "Age": [20, 21, 19, 18],
+            "Marks": [0.9, 0.8, 0.7, 0.6],
+        }
+    )
+
+    test = pd.DataFrame(
+        {
+            "Name": ["tom", "sam", "nick"],
+            "Age": [20, 22, 23],
+            "Marks": [0.9, 0.7, 0.6],
+            "Hobbies": ["tennis", "rugby", "football"],
+        }
+    )
+
+    expected = pd.DataFrame(
+        {
+            "Name": ["tom", "sam", "nick"],
+            "City": [np.nan, np.nan, np.nan],
+            "Age": [20, 22, 23],
+            "Marks": [0.9, 0.7, 0.6],
+        }
+    )
+
+    match_columns = MatchVariables()
+    match_columns.fit(train)
+    df_transformed = match_columns.transform(test)
+
+    assert isinstance(df_transformed, pd.DataFrame)
+    pd.testing.assert_frame_equal(df_transformed, expected)