Skip to content

Commit 060eb08

Browse files
committed
Merge remote-tracking branch 'upstream/master' into depr-cdt-ordered-none
2 parents cf12a1f + d3a1912 commit 060eb08

File tree

11 files changed

+93
-70
lines changed

11 files changed

+93
-70
lines changed

doc/source/whatsnew/v0.25.0.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,10 @@ Deprecations
260260

261261
- The deprecated ``.ix[]`` indexer now raises a more visible FutureWarning instead of DeprecationWarning (:issue:`26438`).
262262
- Deprecated the ``units=M`` (months) and ``units=Y`` (year) parameters for ``units`` of :func:`pandas.to_timedelta`, :func:`pandas.Timedelta` and :func:`pandas.TimedeltaIndex` (:issue:`16344`)
263+
- The :attr:`SparseArray.values` attribute is deprecated. You can use ``np.asarray(...)`` or
264+
the :meth:`SparseArray.to_dense` method instead (:issue:`26421`).
263265
- The functions :func:`pandas.to_datetime` and :func:`pandas.to_timedelta` have deprecated the ``box`` keyword. Instead, use :meth:`to_numpy` or :meth:`Timestamp.to_datetime64` or :meth:`Timedelta.to_timedelta64`. (:issue:`24416`)
264-
- The :meth:`DataFrame.compound` and :meth:`Series.compound` methods are deprecated and will be removed in a future version.
266+
- The :meth:`DataFrame.compound` and :meth:`Series.compound` methods are deprecated and will be removed in a future version (:issue:`26405`).
265267
- The default value ``ordered=None`` in :class:`~pandas.api.types.CategoricalDtype` has been deprecated in favor of ``ordered=False``. When converting between categorical types ``ordered=True`` must be explicitly passed in order to be preserved. (:issue:`26336`)
266268

267269

pandas/_libs/reduction.pyx

+14-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ from numpy cimport (ndarray,
1515
cnp.import_array()
1616

1717
cimport pandas._libs.util as util
18-
from pandas._libs.lib import maybe_convert_objects
18+
from pandas._libs.lib import maybe_convert_objects, values_from_object
1919

2020

2121
cdef _get_result_array(object obj, Py_ssize_t size, Py_ssize_t cnt):
@@ -28,6 +28,14 @@ cdef _get_result_array(object obj, Py_ssize_t size, Py_ssize_t cnt):
2828
return np.empty(size, dtype='O')
2929

3030

31+
cdef bint _is_sparse_array(object obj):
32+
# TODO can be removed one SparseArray.values is removed (GH26421)
33+
if hasattr(obj, '_subtyp'):
34+
if obj._subtyp == 'sparse_array':
35+
return True
36+
return False
37+
38+
3139
cdef class Reducer:
3240
"""
3341
Performs generic reduction operation on a C or Fortran-contiguous ndarray
@@ -146,7 +154,8 @@ cdef class Reducer:
146154
else:
147155
res = self.f(chunk)
148156

149-
if hasattr(res, 'values') and util.is_array(res.values):
157+
if (not _is_sparse_array(res) and hasattr(res, 'values')
158+
and util.is_array(res.values)):
150159
res = res.values
151160
if i == 0:
152161
result = _get_result_array(res,
@@ -432,7 +441,8 @@ cdef class SeriesGrouper:
432441
cdef inline _extract_result(object res):
433442
""" extract the result object, it might be a 0-dim ndarray
434443
or a len-1 0-dim, or a scalar """
435-
if hasattr(res, 'values') and util.is_array(res.values):
444+
if (not _is_sparse_array(res) and hasattr(res, 'values')
445+
and util.is_array(res.values)):
436446
res = res.values
437447
if not np.isscalar(res):
438448
if util.is_array(res):
@@ -635,8 +645,7 @@ def reduce(arr, f, axis=0, dummy=None, labels=None):
635645
raise Exception('Cannot use shortcut')
636646

637647
# pass as an ndarray
638-
if hasattr(labels, 'values'):
639-
labels = labels.values
648+
labels = values_from_object(labels)
640649

641650
reducer = Reducer(arr, f, axis=axis, dummy=dummy, labels=labels)
642651
return reducer.get_result()

pandas/_libs/src/ujson/python/objToJSON.c

+23-3
Original file line numberDiff line numberDiff line change
@@ -210,17 +210,37 @@ static TypeContext *createTypeContext(void) {
210210
return pc;
211211
}
212212

213+
214+
static int is_sparse_array(PyObject *obj) {
215+
// TODO can be removed again once SparseArray.values is removed (GH26421)
216+
if (PyObject_HasAttrString(obj, "_subtyp")) {
217+
PyObject *_subtype = PyObject_GetAttrString(obj, "_subtyp");
218+
PyObject *sparse_array = PyUnicode_FromString("sparse_array");
219+
int ret = PyUnicode_Compare(_subtype, sparse_array);
220+
221+
if (ret == 0) {
222+
return 1;
223+
}
224+
}
225+
return 0;
226+
}
227+
228+
213229
static PyObject *get_values(PyObject *obj) {
214-
PyObject *values = PyObject_GetAttrString(obj, "values");
215-
PRINTMARK();
230+
PyObject *values = NULL;
231+
232+
if (!is_sparse_array(obj)) {
233+
values = PyObject_GetAttrString(obj, "values");
234+
PRINTMARK();
235+
}
216236

217237
if (values && !PyArray_CheckExact(values)) {
218238

219239
if (PyObject_HasAttrString(values, "to_numpy")) {
220240
values = PyObject_CallMethod(values, "to_numpy", NULL);
221241
}
222242

223-
if (PyObject_HasAttrString(values, "values")) {
243+
if (!is_sparse_array(values) && PyObject_HasAttrString(values, "values")) {
224244
PyObject *subvals = get_values(values);
225245
PyErr_Clear();
226246
PRINTMARK();

pandas/core/arrays/sparse.py

+15-34
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@
2121
from pandas.core.dtypes.base import ExtensionDtype
2222
from pandas.core.dtypes.cast import (
2323
astype_nansafe, construct_1d_arraylike_from_scalar, find_common_type,
24-
infer_dtype_from_scalar, maybe_convert_platform)
24+
infer_dtype_from_scalar)
2525
from pandas.core.dtypes.common import (
2626
is_array_like, is_bool_dtype, is_datetime64_any_dtype, is_dtype_equal,
27-
is_integer, is_list_like, is_object_dtype, is_scalar, is_string_dtype,
28-
pandas_dtype)
27+
is_integer, is_object_dtype, is_scalar, is_string_dtype, pandas_dtype)
2928
from pandas.core.dtypes.dtypes import register_extension_dtype
3029
from pandas.core.dtypes.generic import (
3130
ABCIndexClass, ABCSeries, ABCSparseArray, ABCSparseSeries)
@@ -890,7 +889,16 @@ def npoints(self):
890889
def values(self):
891890
"""
892891
Dense values
892+
893+
.. deprecated:: 0.25.0
894+
895+
Use ``np.asarray(...)`` or the ``.to_dense()`` method instead.
893896
"""
897+
msg = (
898+
"The SparseArray.values attribute is deprecated and will be "
899+
"removed in a future version. You can use `np.asarray(...)` or "
900+
"the `.to_dense()` method instead.")
901+
warnings.warn(msg, FutureWarning, stacklevel=2)
894902
return self.to_dense()
895903

896904
def isna(self):
@@ -1076,7 +1084,7 @@ def __getitem__(self, key):
10761084
if is_integer(key):
10771085
return self._get_val_at(key)
10781086
elif isinstance(key, tuple):
1079-
data_slice = self.values[key]
1087+
data_slice = self.to_dense()[key]
10801088
elif isinstance(key, slice):
10811089
# special case to preserve dtypes
10821090
if key == slice(None):
@@ -1635,7 +1643,7 @@ def __array_wrap__(self, array, context=None):
16351643
from pandas.core.dtypes.generic import ABCSparseSeries
16361644

16371645
ufunc, inputs, _ = context
1638-
inputs = tuple(x.values if isinstance(x, ABCSparseSeries) else x
1646+
inputs = tuple(x.to_dense() if isinstance(x, ABCSparseSeries) else x
16391647
for x in inputs)
16401648
return self.__array_ufunc__(ufunc, '__call__', *inputs)
16411649

@@ -1854,37 +1862,10 @@ def _maybe_to_sparse(array):
18541862
array must be SparseSeries or SparseArray
18551863
"""
18561864
if isinstance(array, ABCSparseSeries):
1857-
array = array.values.copy()
1865+
array = array.array.copy()
18581866
return array
18591867

18601868

1861-
def _sanitize_values(arr):
1862-
"""
1863-
return an ndarray for our input,
1864-
in a platform independent manner
1865-
"""
1866-
1867-
if hasattr(arr, 'values'):
1868-
arr = arr.values
1869-
else:
1870-
1871-
# scalar
1872-
if is_scalar(arr):
1873-
arr = [arr]
1874-
1875-
# ndarray
1876-
if isinstance(arr, np.ndarray):
1877-
pass
1878-
1879-
elif is_list_like(arr) and len(arr) > 0:
1880-
arr = maybe_convert_platform(arr)
1881-
1882-
else:
1883-
arr = np.asarray(arr)
1884-
1885-
return arr
1886-
1887-
18881869
def make_sparse(arr, kind='block', fill_value=None, dtype=None, copy=False):
18891870
"""
18901871
Convert ndarray to sparse format
@@ -1902,7 +1883,7 @@ def make_sparse(arr, kind='block', fill_value=None, dtype=None, copy=False):
19021883
(sparse_values, index, fill_value) : (ndarray, SparseIndex, Scalar)
19031884
"""
19041885

1905-
arr = _sanitize_values(arr)
1886+
arr = com.values_from_object(arr)
19061887

19071888
if arr.ndim > 1:
19081889
raise TypeError("expected dimension <= 1 data")

pandas/core/internals/managers.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,8 @@ def apply(self, f, axes=None, filter=None, do_integrity_check=False,
375375
# with a .values attribute.
376376
aligned_args = {k: kwargs[k]
377377
for k in align_keys
378-
if hasattr(kwargs[k], 'values') and
379-
not isinstance(kwargs[k], ABCExtensionArray)}
378+
if not isinstance(kwargs[k], ABCExtensionArray) and
379+
hasattr(kwargs[k], 'values')}
380380

381381
for b in self.blocks:
382382
if filter is not None:

pandas/core/ops.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2272,10 +2272,10 @@ def _cast_sparse_series_op(left, right, opname):
22722272
# TODO: This should be moved to the array?
22732273
if is_integer_dtype(left) and is_integer_dtype(right):
22742274
# series coerces to float64 if result should have NaN/inf
2275-
if opname in ('floordiv', 'mod') and (right.values == 0).any():
2275+
if opname in ('floordiv', 'mod') and (right.to_dense() == 0).any():
22762276
left = left.astype(SparseDtype(np.float64, left.fill_value))
22772277
right = right.astype(SparseDtype(np.float64, right.fill_value))
2278-
elif opname in ('rfloordiv', 'rmod') and (left.values == 0).any():
2278+
elif opname in ('rfloordiv', 'rmod') and (left.to_dense() == 0).any():
22792279
left = left.astype(SparseDtype(np.float64, left.fill_value))
22802280
right = right.astype(SparseDtype(np.float64, right.fill_value))
22812281

pandas/core/sparse/frame.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ def _reindex_index(self, index, method, copy, level, fill_value=np.nan,
627627
# .take returns SparseArray
628628
new = values.take(indexer)
629629
if need_mask:
630-
new = new.values
630+
new = new.to_dense()
631631
# convert integer to float if necessary. need to do a lot
632632
# more than that, handle boolean etc also
633633
new, fill_value = maybe_upcast(new, fill_value=fill_value)

pandas/tests/arrays/sparse/test_array.py

+26-18
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,9 @@ def test_constructor_bool(self):
433433
tm.assert_numpy_array_equal(arr.sp_index.indices,
434434
np.array([2, 3], np.int32))
435435

436-
for dense in [arr.to_dense(), arr.values]:
437-
assert dense.dtype == bool
438-
tm.assert_numpy_array_equal(dense, data)
436+
dense = arr.to_dense()
437+
assert dense.dtype == bool
438+
tm.assert_numpy_array_equal(dense, data)
439439

440440
def test_constructor_bool_fill_value(self):
441441
arr = SparseArray([True, False, True], dtype=None)
@@ -463,9 +463,9 @@ def test_constructor_float32(self):
463463
tm.assert_numpy_array_equal(arr.sp_index.indices,
464464
np.array([0, 2], dtype=np.int32))
465465

466-
for dense in [arr.to_dense(), arr.values]:
467-
assert dense.dtype == np.float32
468-
tm.assert_numpy_array_equal(dense, data)
466+
dense = arr.to_dense()
467+
assert dense.dtype == np.float32
468+
tm.assert_numpy_array_equal(dense, data)
469469

470470
def test_astype(self):
471471
# float -> float
@@ -514,7 +514,7 @@ def test_astype_all(self, any_real_dtype):
514514
assert res.dtype == SparseDtype(typ, 1)
515515
assert res.sp_values.dtype == typ
516516

517-
tm.assert_numpy_array_equal(np.asarray(res.values),
517+
tm.assert_numpy_array_equal(np.asarray(res.to_dense()),
518518
vals.astype(typ))
519519

520520
@pytest.mark.parametrize('array, dtype, expected', [
@@ -596,7 +596,6 @@ def test_copy_shallow(self):
596596
assert arr2.sp_index is self.arr.sp_index
597597

598598
def test_values_asarray(self):
599-
assert_almost_equal(self.arr.values, self.arr_data)
600599
assert_almost_equal(self.arr.to_dense(), self.arr_data)
601600

602601
@pytest.mark.parametrize('data,shape,dtype', [
@@ -627,7 +626,7 @@ def test_dense_repr(self, vals, fill_value, method):
627626

628627
def test_getitem(self):
629628
def _checkit(i):
630-
assert_almost_equal(self.arr[i], self.arr.values[i])
629+
assert_almost_equal(self.arr[i], self.arr.to_dense()[i])
631630

632631
for i in range(len(self.arr)):
633632
_checkit(i)
@@ -641,11 +640,11 @@ def test_getitem_arraylike_mask(self):
641640

642641
def test_getslice(self):
643642
result = self.arr[:-3]
644-
exp = SparseArray(self.arr.values[:-3])
643+
exp = SparseArray(self.arr.to_dense()[:-3])
645644
tm.assert_sp_array_equal(result, exp)
646645

647646
result = self.arr[-4:]
648-
exp = SparseArray(self.arr.values[-4:])
647+
exp = SparseArray(self.arr.to_dense()[-4:])
649648
tm.assert_sp_array_equal(result, exp)
650649

651650
# two corner cases from Series
@@ -654,7 +653,7 @@ def test_getslice(self):
654653
tm.assert_sp_array_equal(result, exp)
655654

656655
result = self.arr[:-12]
657-
exp = SparseArray(self.arr.values[:0])
656+
exp = SparseArray(self.arr.to_dense()[:0])
658657
tm.assert_sp_array_equal(result, exp)
659658

660659
def test_getslice_tuple(self):
@@ -702,16 +701,16 @@ def test_binary_operators(self, op):
702701

703702
def _check_op(op, first, second):
704703
res = op(first, second)
705-
exp = SparseArray(op(first.values, second.values),
704+
exp = SparseArray(op(first.to_dense(), second.to_dense()),
706705
fill_value=first.fill_value)
707706
assert isinstance(res, SparseArray)
708-
assert_almost_equal(res.values, exp.values)
707+
assert_almost_equal(res.to_dense(), exp.to_dense())
709708

710-
res2 = op(first, second.values)
709+
res2 = op(first, second.to_dense())
711710
assert isinstance(res2, SparseArray)
712711
tm.assert_sp_array_equal(res, res2)
713712

714-
res3 = op(first.values, second)
713+
res3 = op(first.to_dense(), second)
715714
assert isinstance(res3, SparseArray)
716715
tm.assert_sp_array_equal(res, res3)
717716

@@ -720,13 +719,13 @@ def _check_op(op, first, second):
720719

721720
# Ignore this if the actual op raises (e.g. pow).
722721
try:
723-
exp = op(first.values, 4)
722+
exp = op(first.to_dense(), 4)
724723
exp_fv = op(first.fill_value, 4)
725724
except ValueError:
726725
pass
727726
else:
728727
assert_almost_equal(res4.fill_value, exp_fv)
729-
assert_almost_equal(res4.values, exp)
728+
assert_almost_equal(res4.to_dense(), exp)
730729

731730
with np.errstate(all="ignore"):
732731
for first_arr, second_arr in [(arr1, arr2), (farr1, farr2)]:
@@ -1230,3 +1229,12 @@ def test_map_missing():
12301229

12311230
result = arr.map({0: 10, 1: 11})
12321231
tm.assert_sp_array_equal(result, expected)
1232+
1233+
1234+
def test_deprecated_values():
1235+
arr = SparseArray([0, 1, 2])
1236+
1237+
with tm.assert_produces_warning(FutureWarning):
1238+
result = arr.values
1239+
1240+
tm.assert_numpy_array_equal(result, arr.to_dense())

pandas/tests/sparse/series/test_series.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def test_constructor(self):
255255
assert isinstance(self.iseries.sp_index, IntIndex)
256256

257257
assert self.zbseries.fill_value == 0
258-
tm.assert_numpy_array_equal(self.zbseries.values.values,
258+
tm.assert_numpy_array_equal(self.zbseries.values.to_dense(),
259259
self.bseries.to_dense().fillna(0).values)
260260

261261
# pass SparseSeries
@@ -322,7 +322,7 @@ def test_constructor_ndarray(self):
322322
def test_constructor_nonnan(self):
323323
arr = [0, 0, 0, nan, nan]
324324
sp_series = SparseSeries(arr, fill_value=0)
325-
tm.assert_numpy_array_equal(sp_series.values.values, np.array(arr))
325+
tm.assert_numpy_array_equal(sp_series.values.to_dense(), np.array(arr))
326326
assert len(sp_series) == 5
327327
assert sp_series.shape == (5, )
328328

@@ -514,7 +514,7 @@ def _compare(idx):
514514
sparse_result = sp.take(idx)
515515
assert isinstance(sparse_result, SparseSeries)
516516
tm.assert_almost_equal(dense_result,
517-
sparse_result.values.values)
517+
sparse_result.values.to_dense())
518518

519519
_compare([1., 2., 3., 4., 5., 0.])
520520
_compare([7, 2, 9, 0, 4])

pandas/util/testing.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,7 @@ def assert_sp_array_equal(left, right, check_dtype=True, check_kind=True,
14031403
assert_attr_equal('fill_value', left, right)
14041404
if check_dtype:
14051405
assert_attr_equal('dtype', left, right)
1406-
assert_numpy_array_equal(left.values, right.values,
1406+
assert_numpy_array_equal(left.to_dense(), right.to_dense(),
14071407
check_dtype=check_dtype)
14081408

14091409

0 commit comments

Comments
 (0)