-
Notifications
You must be signed in to change notification settings - Fork 362
add check_y and check_x_y to check that indexes of X and y match when encoding #410
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fdc7b92
272901c
17133bb
7d3d948
7528219
ee95e31
37d0f9a
92e87e2
95a4cc1
aef0304
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,11 +2,12 @@ | |
| transform(). | ||
| """ | ||
|
|
||
| from typing import List, Union | ||
| from typing import List, Union, Tuple | ||
|
|
||
| import numpy as np | ||
| import pandas as pd | ||
| from scipy.sparse import issparse | ||
| from sklearn.utils.validation import _check_y, check_consistent_length | ||
|
|
||
|
|
||
| def check_X(X: Union[np.generic, np.ndarray, pd.DataFrame]) -> pd.DataFrame: | ||
|
|
@@ -85,6 +86,127 @@ def check_X(X: Union[np.generic, np.ndarray, pd.DataFrame]) -> pd.DataFrame: | |
| return X | ||
|
|
||
|
|
||
| def check_y( | ||
| y: Union[np.generic, np.ndarray, pd.Series, List], | ||
| multi_output: bool = False, | ||
| y_numeric: bool = False, | ||
| ) -> pd.Series: | ||
| """ | ||
| Checks that y is a series, or alternatively, if it can be converted to a series. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| y : pd.Series, np.array, list | ||
| The input to check and copy or transform. | ||
|
|
||
| multi_output : bool, default=False | ||
| Whether to allow 2D y (array). If false, y will be | ||
| validated as a vector. y cannot have np.nan or np.inf values if | ||
| multi_output=True. | ||
|
|
||
| y_numeric : bool, default=False | ||
| Whether to ensure that y has a numeric type. If dtype of y is object, | ||
| it is converted to float64. Should only be used for regression | ||
| algorithms. | ||
|
|
||
| Returns | ||
| ------- | ||
| y: pd.Series | ||
| """ | ||
|
|
||
| if y is None: | ||
| raise ValueError("y cannot be None.") | ||
|
|
||
| elif isinstance(y, pd.Series): | ||
| if y.isnull().any(): | ||
| raise ValueError("y contains NaN values.") | ||
| if y.dtype != "O" and not np.isfinite(y).all(): | ||
| raise ValueError("y contains infinity values.") | ||
| if y_numeric and y.dtype == "O": | ||
| y = y.astype("float") | ||
| y = y.copy() | ||
|
|
||
| else: | ||
| y = _check_y(y, multi_output=multi_output, y_numeric=y_numeric) | ||
| y = pd.Series(y) | ||
|
|
||
| return y | ||
|
|
||
|
|
||
| def check_X_y( | ||
| X: Union[np.generic, np.ndarray, pd.DataFrame], | ||
| y: Union[np.generic, np.ndarray, pd.Series, List], | ||
| multi_output: bool = False, | ||
| y_numeric: bool = False, | ||
| ) -> Tuple[pd.DataFrame, pd.Series]: | ||
| """ | ||
| Ensures X and y are compatible pandas DataFrame and Series. If both are pandas | ||
| objects, checks that their indexes match. If any is a numpy array, converts to | ||
| pandas object with compatible index. | ||
|
|
||
| This transformer ensures that we can concatenate X and y using `pandas.concat`, | ||
| functionality needed in the encoders. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| X: Pandas DataFrame or numpy ndarray | ||
| The input to check and copy or transform. | ||
|
|
||
| y: pd.Series, np.array, list | ||
| The input to check and copy or transform. | ||
|
|
||
| multi_output : bool, default=False | ||
| Whether to allow 2D y (array). If false, y will be | ||
| validated as a vector. y cannot have np.nan or np.inf values if | ||
| multi_output=True. | ||
|
|
||
| y_numeric : bool, default=False | ||
| Whether to ensure that y has a numeric type. If dtype of y is object, | ||
| it is converted to float64. Should only be used for regression | ||
| algorithms. | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError: if X and y are pandas objects with inconsistent indexes. | ||
| TypeError: if X is sparse matrix, empty dataframe or not a dataframe. | ||
| TypeError: if y can't be parsed as pandas Series. | ||
|
|
||
| Returns | ||
| ------- | ||
| X: Pandas DataFrame | ||
| y: Pandas Series | ||
| """ | ||
|
|
||
| def _check_X_y(X, y): | ||
| X = check_X(X) | ||
| y = check_y(y, multi_output=multi_output, y_numeric=y_numeric) | ||
| check_consistent_length(X, y) | ||
| return X, y | ||
|
Comment on lines
+180
to
+184
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In every case below you call this function, so consider just running this code first without defining it as a local function.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, makes sense. The thing is, if I ran this function first, then X and y would be a pandas df and series, so I can't really check for the different scenarios any more. That's why I took this convoluted approach instead. How would you approach it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, of course. This is fine then. You could also maybe define "the" index in cases, then do the checks/conversions? |
||
|
|
||
| # case 1: both are pandas objects | ||
| if isinstance(X, pd.DataFrame) and isinstance(y, pd.Series): | ||
| X, y = _check_X_y(X, y) | ||
| # Check that their indexes match. | ||
| if not all(y.index == X.index): | ||
| raise ValueError("The indexes of X and y do not match.") | ||
|
|
||
| # case 2: X is dataframe and y is something else | ||
| if isinstance(X, pd.DataFrame) and not isinstance(y, pd.Series): | ||
| X, y = _check_X_y(X, y) | ||
| y.index = X.index | ||
|
|
||
| # case 3: X is not a dataframe and y is a series | ||
| elif not isinstance(X, pd.DataFrame) and isinstance(y, pd.Series): | ||
| X, y = _check_X_y(X, y) | ||
| X.index = y.index | ||
|
|
||
| # all other cases | ||
| else: | ||
| X, y = _check_X_y(X, y) | ||
|
|
||
| return X, y | ||
|
|
||
|
|
||
| def _check_X_matches_training_df(X: pd.DataFrame, reference: int) -> None: | ||
| """ | ||
| Checks that DataFrame to transform has the same number of columns that the | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default in docstring disagrees with code default