Skip to content

Avoid mapping pandas.SparseDtype to Unknown #3722

Description

@maxzw

Describe the bug

Narwhals maps pandas sparse columns to Unknown in schema inference, even though those columns have clear underlying dtypes (for example Sparse[int64, 0], Sparse[float64, 0.0], Sparse[bool, False]).

This appears inconsistent with documentation that says the pandas API is fully supported.

Steps or code to reproduce the bug

#!/usr/bin/env python3
import numpy as np
import pandas as pd
import narwhals as nw

rng = np.random.default_rng(0)
df_sparse = pd.DataFrame(
    {
        "A": pd.arrays.SparseArray(rng.permutation([0, 1, 2] * 10)),
        "B": pd.arrays.SparseArray(rng.permutation([0.0, 0.1, 0.2, -0.1, 0.2] * 6)),
        "C": pd.arrays.SparseArray(rng.permutation([True, False] * 15)),
    }
)
df_dense = df_sparse.sparse.to_dense()

sparse_schema = nw.from_native(df_sparse).schema
dense_schema = nw.from_native(df_dense).schema

print("sparse schema:", sparse_schema)
print("dense schema:", dense_schema)

# These operations still execute and produce the same values as the dense frame.
selected_sparse = nw.from_native(df_sparse).select("A", "B").to_native().sparse.to_dense()
selected_dense = nw.from_native(df_dense).select("A", "B").to_native()
print("select(A, B) matches dense output:", selected_sparse.equals(selected_dense))

filtered_sparse = nw.from_native(df_sparse).filter(nw.col("A") > 0).to_native().sparse.to_dense()
filtered_dense = nw.from_native(df_dense).filter(nw.col("A") > 0).to_native()
print("filter(A > 0) matches dense output:", filtered_sparse.equals(filtered_dense))

with_columns_sparse = nw.from_native(df_sparse).with_columns(double_A=nw.col("A") * 2).to_native().sparse.to_dense()
with_columns_dense = nw.from_native(df_dense).with_columns(double_A=nw.col("A") * 2).to_native()
print("with_columns(double_A) matches dense output:", with_columns_sparse.equals(with_columns_dense))

Expected results

Narwhals should infer typed columns for pandas sparse arrays (for example Int64, Float64, Boolean) instead of Unknown.

Actual results

sparse schema: Schema({'A': Unknown, 'B': Unknown, 'C': Unknown})
dense schema: Schema({'A': Int64, 'B': Float64, 'C': Boolean})
select(A, B) matches dense output: True
filter(A > 0) matches dense output: True
with_columns(double_A) matches dense output: True

Please run narwhals.show_versions() and enter the output below.

System:
    python: 3.13.13 | packaged by Anaconda, Inc. | (main, Apr 14 2026, 06:14:06) [Clang 20.1.8 ]
executable: /Users/pnl0vq13/miniconda3/envs/lightgbm-dev/bin/python
   machine: macOS-26.5.1-arm64-arm-64bit-Mach-O

Python dependencies:
     narwhals: 2.22.1
        numpy: 2.4.4
       pandas: 3.0.2
        modin:
         cudf:
      pyarrow: 24.0.0
      pyspark:
       polars: 1.30.0
         dask:
       duckdb:
         ibis:
     sqlframe:

Relevant log output

Additional information

Metadata

Metadata

Assignees

No one assigned

    Labels

    dtypesenhancementNew feature or requestpandas-likeIssue is related to pandas-like backends

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions