Skip to content

Commit 376a05e

Browse files
VikramjeetDjreback
authored andcommitted
DEPR: Deprecate Series/Dataframe.to_dense/to_sparse (#26684)
1 parent 9ceb029 commit 376a05e

23 files changed

+117
-15
lines changed

doc/source/whatsnew/v0.25.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ Other Deprecations
503503
- The :meth:`Series.ftype`, :meth:`Series.ftypes` and :meth:`DataFrame.ftypes` methods are deprecated and will be removed in a future version.
504504
Instead, use :meth:`Series.dtype` and :meth:`DataFrame.dtypes` (:issue:`26705`).
505505
- :meth:`Timedelta.resolution` is deprecated and replaced with :meth:`Timedelta.resolution_string`. In a future version, :meth:`Timedelta.resolution` will be changed to behave like the standard library :attr:`timedelta.resolution` (:issue:`21344`)
506+
- :meth:`Series.to_sparse`, :meth:`DataFrame.to_sparse`, :meth:`Series.to_dense` and :meth:`DataFrame.to_dense` are deprecated and will be removed in a future version. (:issue:`26557`).
506507

507508
.. _whatsnew_0250.prior_deprecations:
508509

pandas/core/frame.py

+10-3
Original file line numberDiff line numberDiff line change
@@ -1889,6 +1889,8 @@ def to_sparse(self, fill_value=None, kind='block'):
18891889
"""
18901890
Convert to SparseDataFrame.
18911891
1892+
.. deprecated:: 0.25.0
1893+
18921894
Implement the sparse version of the DataFrame meaning that any data
18931895
matching a specific value it's omitted in the representation.
18941896
The sparse DataFrame allows for a more efficient storage.
@@ -1939,10 +1941,15 @@ def to_sparse(self, fill_value=None, kind='block'):
19391941
>>> type(sdf) # doctest: +SKIP
19401942
<class 'pandas.core.sparse.frame.SparseDataFrame'>
19411943
"""
1944+
warnings.warn("DataFrame.to_sparse is deprecated and will be removed "
1945+
"in a future version", FutureWarning, stacklevel=2)
1946+
19421947
from pandas.core.sparse.api import SparseDataFrame
1943-
return SparseDataFrame(self._series, index=self.index,
1944-
columns=self.columns, default_kind=kind,
1945-
default_fill_value=fill_value)
1948+
with warnings.catch_warnings():
1949+
warnings.filterwarnings("ignore", message="SparseDataFrame")
1950+
return SparseDataFrame(self._series, index=self.index,
1951+
columns=self.columns, default_kind=kind,
1952+
default_fill_value=fill_value)
19461953

19471954
@deprecate_kwarg(old_arg_name='encoding', new_arg_name=None)
19481955
def to_stata(self, fname, convert_dates=None, write_index=True,

pandas/core/generic.py

+5
Original file line numberDiff line numberDiff line change
@@ -1940,11 +1940,16 @@ def to_dense(self):
19401940
"""
19411941
Return dense representation of NDFrame (as opposed to sparse).
19421942
1943+
.. deprecated:: 0.25.0
1944+
19431945
Returns
19441946
-------
19451947
%(klass)s
19461948
Dense %(klass)s.
19471949
"""
1950+
warnings.warn("DataFrame/Series.to_dense is deprecated "
1951+
"and will be removed in a future version",
1952+
FutureWarning, stacklevel=2)
19481953
# compat
19491954
return self
19501955

pandas/core/groupby/ops.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -630,9 +630,9 @@ def _aggregate_series_fast(self, obj, func):
630630
group_index, _, ngroups = self.group_info
631631

632632
# avoids object / Series creation overhead
633-
dummy = obj._get_values(slice(None, 0)).to_dense()
633+
dummy = obj._get_values(slice(None, 0))
634634
indexer = get_group_index_sorter(group_index, ngroups)
635-
obj = obj._take(indexer).to_dense()
635+
obj = obj._take(indexer)
636636
group_index = algorithms.take_nd(
637637
group_index, indexer, allow_fill=False)
638638
grouper = reduction.SeriesGrouper(obj, func, group_index, ngroups,
@@ -879,7 +879,7 @@ def apply(self, f):
879879
class SeriesSplitter(DataSplitter):
880880

881881
def _chop(self, sdata, slice_obj):
882-
return sdata._get_values(slice_obj).to_dense()
882+
return sdata._get_values(slice_obj)
883883

884884

885885
class FrameSplitter(DataSplitter):

pandas/core/series.py

+10-3
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,8 @@ def to_sparse(self, kind='block', fill_value=None):
15921592
"""
15931593
Convert Series to SparseSeries.
15941594
1595+
.. deprecated:: 0.25.0
1596+
15951597
Parameters
15961598
----------
15971599
kind : {'block', 'integer'}, default 'block'
@@ -1603,12 +1605,17 @@ def to_sparse(self, kind='block', fill_value=None):
16031605
SparseSeries
16041606
Sparse representation of the Series.
16051607
"""
1608+
1609+
warnings.warn("Series.to_sparse is deprecated and will be removed "
1610+
"in a future version", FutureWarning, stacklevel=2)
16061611
from pandas.core.sparse.series import SparseSeries
16071612

16081613
values = SparseArray(self, kind=kind, fill_value=fill_value)
1609-
return SparseSeries(
1610-
values, index=self.index, name=self.name
1611-
).__finalize__(self)
1614+
with warnings.catch_warnings():
1615+
warnings.filterwarnings("ignore", message="SparseSeries")
1616+
return SparseSeries(
1617+
values, index=self.index, name=self.name
1618+
).__finalize__(self)
16121619

16131620
def _set_name(self, name, inplace=False):
16141621
"""

pandas/tests/arrays/sparse/test_arithmetics.py

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010

1111
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
12+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
1213
class TestSparseArrayArithmetics:
1314

1415
_base = np.array

pandas/tests/generic/test_generic.py

+14
Original file line numberDiff line numberDiff line change
@@ -918,3 +918,17 @@ def test_axis_classmethods(self, box):
918918
assert obj._get_axis_name(v) == box._get_axis_name(v)
919919
assert obj._get_block_manager_axis(v) == \
920920
box._get_block_manager_axis(v)
921+
922+
def test_deprecated_to_dense(self):
923+
# GH 26557: DEPR
924+
# Deprecated 0.25.0
925+
926+
df = pd.DataFrame({"A": [1, 2, 3]})
927+
with tm.assert_produces_warning(FutureWarning):
928+
result = df.to_dense()
929+
tm.assert_frame_equal(result, df)
930+
931+
ser = pd.Series([1, 2, 3])
932+
with tm.assert_produces_warning(FutureWarning):
933+
result = ser.to_dense()
934+
tm.assert_series_equal(result, ser)

pandas/tests/io/json/test_pandas.py

+2
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,8 @@ def test_datetime_tz(self):
10131013
assert stz.to_json() == s_naive.to_json()
10141014

10151015
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
1016+
@pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")
1017+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
10161018
def test_sparse(self):
10171019
# GH4377 df.to_json segfaults with non-ndarray blocks
10181020
df = pd.DataFrame(np.random.randn(10, 4))

pandas/tests/io/test_packers.py

+2
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,8 @@ def test_dataframe_duplicate_column_names(self):
551551

552552

553553
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
554+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
555+
@pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")
554556
class TestSparse(TestPackers):
555557

556558
def _check_roundtrip(self, obj, comparator, **kwargs):

pandas/tests/io/test_pytables.py

+10
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@
5151
"ignore:object name:tables.exceptions.NaturalNameWarning"
5252
)
5353
ignore_sparse = pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
54+
ignore_dataframe_tosparse = pytest.mark.filterwarnings(
55+
"ignore:DataFrame.to_sparse:FutureWarning"
56+
)
57+
ignore_series_tosparse = pytest.mark.filterwarnings(
58+
"ignore:Series.to_sparse:FutureWarning"
59+
)
5460

5561
# contextmanager to ensure the file cleanup
5662

@@ -2245,6 +2251,7 @@ def test_series(self):
22452251
check_index_type=False)
22462252

22472253
@ignore_sparse
2254+
@ignore_series_tosparse
22482255
def test_sparse_series(self):
22492256

22502257
s = tm.makeStringSeries()
@@ -2262,6 +2269,7 @@ def test_sparse_series(self):
22622269
check_series_type=True)
22632270

22642271
@ignore_sparse
2272+
@ignore_dataframe_tosparse
22652273
def test_sparse_frame(self):
22662274

22672275
s = tm.makeDataFrame()
@@ -2601,6 +2609,7 @@ def test_overwrite_node(self):
26012609
tm.assert_series_equal(store['a'], ts)
26022610

26032611
@ignore_sparse
2612+
@ignore_dataframe_tosparse
26042613
def test_sparse_with_compression(self):
26052614

26062615
# GH 2931
@@ -3746,6 +3755,7 @@ def test_start_stop_multiple(self):
37463755
tm.assert_frame_equal(result, expected)
37473756

37483757
@ignore_sparse
3758+
@ignore_dataframe_tosparse
37493759
def test_start_stop_fixed(self):
37503760

37513761
with ensure_clean_store(self.path) as store:

pandas/tests/series/test_api.py

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ def test_sort_index_name(self):
123123
assert result.name == self.ts.name
124124

125125
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
126+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
126127
def test_to_sparse_pass_name(self):
127128
result = self.ts.to_sparse()
128129
assert result.name == self.ts.name

pandas/tests/series/test_combine_concat.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ def test_combine_first_dt_tz_values(self, tz_naive_fixture):
212212
assert_series_equal(exp, result)
213213

214214
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
215+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
215216
def test_concat_empty_series_dtypes(self):
216217

217218
# booleans
@@ -244,16 +245,16 @@ def test_concat_empty_series_dtypes(self):
244245

245246
# sparse
246247
# TODO: move?
247-
result = pd.concat([Series(dtype='float64').to_sparse(), Series(
248-
dtype='float64').to_sparse()])
248+
result = pd.concat([Series(dtype='float64').to_sparse(),
249+
Series(dtype='float64').to_sparse()])
249250
assert result.dtype == 'Sparse[float64]'
250251

251252
# GH 26705 - Assert .ftype is deprecated
252253
with tm.assert_produces_warning(FutureWarning):
253254
assert result.ftype == 'float64:sparse'
254255

255-
result = pd.concat([Series(dtype='float64').to_sparse(), Series(
256-
dtype='float64')])
256+
result = pd.concat([Series(dtype='float64').to_sparse(),
257+
Series(dtype='float64')])
257258
# TODO: release-note: concat sparse dtype
258259
expected = pd.core.sparse.api.SparseDtype(np.float64)
259260
assert result.dtype == expected
@@ -262,8 +263,8 @@ def test_concat_empty_series_dtypes(self):
262263
with tm.assert_produces_warning(FutureWarning):
263264
assert result.ftype == 'float64:sparse'
264265

265-
result = pd.concat([Series(dtype='float64').to_sparse(), Series(
266-
dtype='object')])
266+
result = pd.concat([Series(dtype='float64').to_sparse(),
267+
Series(dtype='object')])
267268
# TODO: release-note: concat sparse dtype
268269
expected = pd.core.sparse.api.SparseDtype('object')
269270
assert result.dtype == expected

pandas/tests/series/test_missing.py

+2
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,7 @@ def test_series_fillna_limit(self):
781781
assert_series_equal(result, expected)
782782

783783
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
784+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
784785
def test_sparse_series_fillna_limit(self):
785786
index = np.arange(10)
786787
s = Series(np.random.randn(10), index=index)
@@ -809,6 +810,7 @@ def test_sparse_series_fillna_limit(self):
809810
assert_series_equal(result, expected)
810811

811812
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
813+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
812814
def test_sparse_series_pad_backfill_limit(self):
813815
index = np.arange(10)
814816
s = Series(np.random.randn(10), index=index)

pandas/tests/sparse/frame/test_apply.py

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def fill_frame(frame):
3838

3939

4040
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
41+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
4142
def test_apply(frame):
4243
applied = frame.apply(np.sqrt)
4344
assert isinstance(applied, SparseDataFrame)
@@ -72,6 +73,7 @@ def test_apply_empty(empty):
7273

7374

7475
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
76+
@pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")
7577
def test_apply_nonuq():
7678
orig = DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]],
7779
index=['a', 'a', 'c'])

pandas/tests/sparse/frame/test_frame.py

+16
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ def test_deprecated():
2525

2626

2727
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
28+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
29+
@pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")
2830
class TestSparseDataFrame(SharedWithSparse):
2931
klass = SparseDataFrame
3032

@@ -348,6 +350,18 @@ def test_dense_to_sparse(self):
348350
assert sdf.default_fill_value == 0
349351
tm.assert_frame_equal(sdf.to_dense(), df)
350352

353+
def test_deprecated_dense_to_sparse(self):
354+
# GH 26557
355+
# Deprecated 0.25.0
356+
357+
df = pd.DataFrame({"A": [1, np.nan, 3]})
358+
sparse_df = pd.SparseDataFrame({"A": [1, np.nan, 3]})
359+
360+
with tm.assert_produces_warning(FutureWarning,
361+
check_stacklevel=False):
362+
result = df.to_sparse()
363+
tm.assert_frame_equal(result, sparse_df)
364+
351365
def test_density(self):
352366
df = SparseSeries([nan, nan, nan, 0, 1, 2, 3, 4, 5, 6])
353367
assert df.density == 0.7
@@ -1294,6 +1308,7 @@ def test_default_fill_value_with_no_data(self):
12941308

12951309

12961310
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
1311+
@pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")
12971312
class TestSparseDataFrameArithmetic:
12981313

12991314
def test_numeric_op_scalar(self):
@@ -1324,6 +1339,7 @@ def test_comparison_op_scalar(self):
13241339

13251340

13261341
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
1342+
@pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")
13271343
class TestSparseDataFrameAnalytics:
13281344

13291345
def test_cumsum(self, float_frame):

pandas/tests/sparse/frame/test_to_csv.py

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
9+
@pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")
910
class TestSparseDataFrameToCsv:
1011
fill_values = [np.nan, 0, None, 1]
1112

pandas/tests/sparse/frame/test_to_from_scipy.py

+1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ def test_from_scipy_fillna(spmatrix):
174174

175175

176176
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
177+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
177178
def test_index_names_multiple_nones():
178179
# https://github.com./pandas-dev/pandas/pull/24092
179180
sparse = pytest.importorskip("scipy.sparse")

pandas/tests/sparse/series/test_series.py

+19
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def _test_data2_zero():
6161

6262

6363
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
64+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
6465
class TestSparseSeries(SharedWithSparse):
6566

6667
series_klass = SparseSeries
@@ -1045,6 +1046,7 @@ def test_memory_usage_deep(self, deep, fill_value):
10451046

10461047

10471048
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
1049+
@pytest.mark.filterwarnings("ignore:DataFrame.to_sparse:FutureWarning")
10481050
class TestSparseHandlingMultiIndexes:
10491051

10501052
def setup_method(self, method):
@@ -1076,6 +1078,7 @@ def test_round_trip_preserve_multiindex_names(self):
10761078
"ignore:the matrix subclass:PendingDeprecationWarning"
10771079
)
10781080
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
1081+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
10791082
class TestSparseSeriesScipyInteraction:
10801083
# Issue 8048: add SparseSeries coo methods
10811084

@@ -1444,6 +1447,7 @@ def _dense_series_compare(s, f):
14441447

14451448

14461449
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
1450+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
14471451
class TestSparseSeriesAnalytics:
14481452

14491453
def setup_method(self, method):
@@ -1538,6 +1542,7 @@ def test_constructor_dict_datetime64_index(datetime_type):
15381542

15391543

15401544
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
1545+
@pytest.mark.filterwarnings("ignore:Series.to_sparse:FutureWarning")
15411546
def test_to_sparse():
15421547
# https://github.com./pandas-dev/pandas/issues/22389
15431548
arr = pd.SparseArray([1, 2, None, 3])
@@ -1546,6 +1551,20 @@ def test_to_sparse():
15461551
tm.assert_sp_array_equal(result.values, arr, check_kind=False)
15471552

15481553

1554+
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
1555+
def test_deprecated_to_sparse():
1556+
# GH 26557
1557+
# Deprecated 0.25.0
1558+
1559+
ser = Series([1, np.nan, 3])
1560+
sparse_ser = pd.SparseSeries([1, np.nan, 3])
1561+
1562+
with tm.assert_produces_warning(FutureWarning,
1563+
check_stacklevel=False):
1564+
result = ser.to_sparse()
1565+
tm.assert_series_equal(result, sparse_ser)
1566+
1567+
15491568
@pytest.mark.filterwarnings("ignore:Sparse:FutureWarning")
15501569
def test_constructor_mismatched_raises():
15511570
msg = "Length of passed values is 2, index implies 3"

0 commit comments

Comments
 (0)