Thanks to visit codestin.com
Credit goes to github.com

Skip to content

FIX check_array with narwhals.DataFrame input - #34051

Merged
jeremiedbb merged 8 commits into
scikit-learn:mainfrom
lorentzenchr:nw_check_array
May 29, 2026
Merged

FIX check_array with narwhals.DataFrame input#34051
jeremiedbb merged 8 commits into
scikit-learn:mainfrom
lorentzenchr:nw_check_array

Conversation

@lorentzenchr

Copy link
Copy Markdown
Member

Reference Issues/PRs

Fixes a bug in check_array introduced in #33971, popped up in #33959.

What does this implement/fix? Explain your changes.

Input in check_array may already be a narwhals.DataFrame. This errors on main and is fixed here with a test for it.

AI usage disclosure

None

Any other comments?

@lorentzenchr lorentzenchr added this to the 1.9 milestone May 18, 2026
@lorentzenchr lorentzenchr changed the title Nw check array FIX check_array with narwhals.DataFrame input May 18, 2026
Comment on lines 888 to 891
if _nw_into_df_or_series(array):
array_df = nw.from_native(array, allow_series=True)
else:
array_df = None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

maybe we shoudl already define df_pandas here, instead of asking and array_df.implementation.is_pandas() afterwards ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I like relying on nw for which backend is used.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

yeah but the flow is weird here. We only use array_df if it comes from pandas.

if _nw_into_df_or_series(array):
    array_df = nw.from_native(array, allow_series=True)
else:
    array_df = None

if array_df is not None and array_df.implentation.is_pandas():
    df_pandas = array_df.to_native()

    # and then only use df_pandas in this branch

I think the following would be more readable:

if _nw_into_df_or_series(array):
    array_df = nw.from_native(array, allow_series=True)
    array_df = array_df.to_native() if array_df.implentation.is_pandas() else None
else:
    array_df = None

if array_df is not None:
    # do everything with array_df

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This part is not touched by this PR. Also, I anticipate that array_df will be used more within this function in the future.

@FrancoisPgm FrancoisPgm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you @lorentzenchr , I have just a couple of questions and nitpicks but otherwise from what I can tell this looks good.

Comment thread sklearn/utils/validation.py Outdated
Comment thread sklearn/utils/_testing.py Outdated
assert not np.isnan(M).any()


@pytest.mark.filterwarnings("ignore::scipy.sparse.SparseEfficiencyWarning")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does the warning result from the changes in check_array ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No. a8d8983 is not related to the bugfix, but removes all warnings in the tests such that I could run pytest -x -We sklearn/utils/tests/tests_validation.py successfully.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Haha if that's your goal, you have a loooong path in front of you 😄 (#29516)

@lorentzenchr lorentzenchr May 20, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I‘ve already been quite successful in linear models (the ones I touched).

X = retype(np.arange(4).reshape(2, 2).astype(float))
X = np.array(np.arange(4).reshape(2, 2).astype(float))
X[0, 0] = value
X = retype(X)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I believe this change is here to avoid the SparseEfficiencyWarning, is that correct ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correct.

Comment thread sklearn/utils/tests/test_validation.py
Comment thread sklearn/utils/_testing.py Outdated
Comment on lines +1002 to +1015
convert_to_nw = False
if constructor_name == "narwhals":
convert_to_nw = True
# Search for backend.
for lib_name in ["pandas", "polars"]:
try:
sys.modules[lib_name]
constructor_name = lib_name
break
except KeyError:
continue
else:
pytest.skip("no dataframe backend for narwhals is installed")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

feels like maybe constructor_name is not the best place for it. To me we should be able to use _convert_container to create a narwhals dataframe backed by a pandas or polars dataframe without having to create a dataframe first. Something like

X = np.array([[1, 2], [3, 4]])
df = _convert_container(X, "pandas", convert_to_narwhals=True)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I see it different. Either nw.df is an option in constructor name, or we don’t deal with nw in _convert_container.
We could also simplify and require in the tests that, e.g., pandas is available to construct nw.df (and rely on ne testing that the backend does not matter).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Still it's weird that you can't chose the backend and that the backend that one gets is based on an hardcoded ordering. For instance, in the test that check sparse you added:

    sdf = pd.DataFrame.sparse.from_spmatrix(sp_mat)
    if convert_to_narwhals:
        sdf = _convert_container(sdf, constructor_name="narwhals")

If the order was different, it would not do what's expected. That's fragile.
(in particular there's no way, with this ordering, to get a narwhals dataframe with a polars backend if pandas is installed)

Maybe here it would just be more appropriate and robust to do

    sdf = pd.DataFrame.sparse.from_spmatrix(sp_mat)
    if convert_to_narwhals:
        sdf = nw.from_native(sdf)

@jeremiedbb jeremiedbb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I removed the changes to _convert_container since it was not really used anymore. Later I think we'll prefer to think narwhals inclusion jointly with #28681.

LGTM

@jeremiedbb
jeremiedbb enabled auto-merge (squash) May 29, 2026 11:35
@jeremiedbb
jeremiedbb merged commit 01dddb9 into scikit-learn:main May 29, 2026
36 checks passed
@lorentzenchr

Copy link
Copy Markdown
Member Author

While well intended, 916bbd7 effectively removes the test that this PR fixes!!!

@jeremiedbb

jeremiedbb commented May 29, 2026

Copy link
Copy Markdown
Member

I'm not so sure. Was check_array already expected to work on narwhals dataframes ?
To me the bug doesn't exist yet, but will when we start using narwhals across public functions and not just internally. There's for instance no test that you can fit an estimator on a narwhals dataframe. So in fact I don't think that this PR needs to be in 1.9 because it should not have a impact on users if I'm not missing something.

(also, not all tests: the sparse test is still there)

@lorentzenchr
lorentzenchr deleted the nw_check_array branch May 31, 2026 08:55
@jeremiedbb jeremiedbb mentioned this pull request Jun 1, 2026
16 tasks
prady0t pushed a commit to prady0t/scikit-learn that referenced this pull request Sep 2, 2026
@jeremiedbb jeremiedbb mentioned this pull request Sep 8, 2026
14 tasks
jeremiedbb added a commit that referenced this pull request Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants