From 4fbb5a270eba32bb95be1368a5fe741a98be25d8 Mon Sep 17 00:00:00 2001 From: Pratyush Adhikari Date: Wed, 19 Aug 2026 00:32:08 +0530 Subject: [PATCH] GH-50906: [Python] Reshape 1D tensors to 2D in SparseCSR/CSC matrix conversion --- python/pyarrow/tensor.pxi | 6 ++++++ python/pyarrow/tests/test_sparse_tensor.py | 23 +++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/python/pyarrow/tensor.pxi b/python/pyarrow/tensor.pxi index 521ee0c3f44f..ca43e14c553f 100644 --- a/python/pyarrow/tensor.pxi +++ b/python/pyarrow/tensor.pxi @@ -840,6 +840,9 @@ shape: {self.shape}""" if not isinstance(obj, (scipy.sparse.csr_array, scipy.sparse.csr_matrix)): raise TypeError( f"Expected scipy.sparse.csr_array or scipy.sparse.csr_matrix, got {type(obj)}") + if obj.ndim != 2: + raise ValueError("Expected 2-dimensional sparse input for " + "SparseCSRMatrix") cdef shared_ptr[CSparseCSRMatrix] csparse_tensor cdef vector[int64_t] c_shape @@ -1111,6 +1114,9 @@ shape: {self.shape}""" if not isinstance(obj, (scipy.sparse.csc_array, scipy.sparse.csc_matrix)): raise TypeError( f"Expected scipy.sparse.csc_array or scipy.sparse.csc_matrix, got {type(obj)}") + if obj.ndim != 2: + raise ValueError("Expected 2-dimensional sparse input for " + "SparseCSCMatrix") cdef shared_ptr[CSparseCSCMatrix] csparse_tensor cdef vector[int64_t] c_shape diff --git a/python/pyarrow/tests/test_sparse_tensor.py b/python/pyarrow/tests/test_sparse_tensor.py index eca8090d77a9..cdbae8f87da8 100644 --- a/python/pyarrow/tests/test_sparse_tensor.py +++ b/python/pyarrow/tests/test_sparse_tensor.py @@ -26,10 +26,13 @@ import pyarrow as pa try: - from scipy.sparse import csr_array, coo_array, csr_matrix, coo_matrix + from scipy.sparse import ( + csr_array, coo_array, csr_matrix, csc_matrix, coo_matrix + ) except ImportError: coo_matrix = None csr_matrix = None + csc_matrix = None csr_array = None coo_array = None @@ -254,6 +257,24 @@ def test_sparse_csr_matrix_from_dense(dtype_str, arrow_type): assert np.array_equal(indices, result_indices) +@pytest.mark.skipif(not csr_matrix, reason="requires scipy") +@pytest.mark.parametrize('pa_class,sc_class', [ + pytest.param(pa.SparseCSRMatrix, csr_matrix, id='CSR'), + pytest.param(pa.SparseCSCMatrix, csc_matrix, id='CSC'), +]) +def test_sparse_csx_matrix_from_1d(pa_class, sc_class): + array = np.array([1, 0, 2, 0, 0, 3, 0, 4], dtype=np.int64) + + # csr_matrix/csc_matrix normalize 1D input to (1, n) + scipy_matrix = sc_class(array) + + # Test from 1D scipy matrix + sparse_tensor = pa_class.from_scipy(scipy_matrix) + assert np.array_equal( + sparse_tensor.to_tensor().to_numpy(), scipy_matrix.toarray() + ) + + @pytest.mark.parametrize('dtype_str,arrow_type', tensor_type_pairs) def test_sparse_csf_tensor_from_dense_numpy(dtype_str, arrow_type): dtype = np.dtype(dtype_str)