Skip to content

Commit 3e8b076

Browse files
committed
fixup
1 parent 5dbc96d commit 3e8b076

File tree

5 files changed

+38
-33
lines changed

5 files changed

+38
-33
lines changed

pandas/core/internals.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,16 +1733,15 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0,
17331733
"""
17341734
inplace = validate_bool_kwarg(inplace, 'inplace')
17351735

1736-
# use block's copy logic.
1736+
new_values, _, new, _ = self._try_coerce_args(self.values, new)
17371737
# .values may be an Index which does shallow copy by default
1738-
new_values = self.values if inplace else self.copy().values
1739-
new_values, _, new, _ = self._try_coerce_args(new_values, new)
1738+
if not inplace:
1739+
new_values = new_values.copy(deep=True)
17401740

1741-
# Cannot modify a SparseArray
17421741
if is_sparse(new_values):
1743-
new_values = new_values.to_dense()
1744-
if is_sparse(mask):
1745-
mask = mask.to_dense()
1742+
indexer = mask.to_dense().values.ravel().nonzero()[0]
1743+
block = self.copy().setitem(indexer, new)
1744+
return [block]
17461745

17471746
if isinstance(new, np.ndarray) and len(new) == len(mask):
17481747
new = new[mask]
@@ -2766,7 +2765,10 @@ def _can_hold_element(self, element):
27662765
return np.can_cast(np.asarray(element).dtype, self.sp_values.dtype)
27672766

27682767
def _try_coerce_result(self, result):
2769-
if np.ndim(result) > 0 and not is_sparse(result):
2768+
if (
2769+
# isinstance(result, np.ndarray) and
2770+
np.ndim(result) > 0
2771+
and not is_sparse(result)):
27702772
result = SparseArray(result, kind=self.kind,
27712773
fill_value=self.fill_value, dtype=self.dtype)
27722774
return result
@@ -3768,7 +3770,8 @@ def fast_xs(self, loc):
37683770
# Such assignment may incorrectly coerce NaT to None
37693771
# result[blk.mgr_locs] = blk._slice((slice(None), loc))
37703772
for i, rl in enumerate(blk.mgr_locs):
3771-
result[rl] = blk._try_coerce_result(blk.iget((i, loc)))
3773+
# result[rl] = blk._try_coerce_result(blk.iget((i, loc)))
3774+
result[rl] = blk.iget((i, loc))
37723775

37733776
return result
37743777

pandas/core/sparse/array.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ def set_values(self, indexer, value):
402402
warnings.warn(
403403
'Setting SparseSeries/Array values is particularly '
404404
'inefficient when indexing with multiple keys because the '
405-
'whole series series is made dense interim.',
405+
'whole series is made dense interim.',
406406
PerformanceWarning, stacklevel=2)
407407

408408
values = self.to_dense()
@@ -412,7 +412,7 @@ def set_values(self, indexer, value):
412412

413413
warnings.warn(
414414
'Setting SparseSeries/Array values is inefficient '
415-
'(a copy of data is made)', PerformanceWarning, stacklevel=2)
415+
'(a copy of data is made).', PerformanceWarning, stacklevel=2)
416416

417417
# If label already in sparse index, just switch the value on a copy
418418
idx = self.sp_index.lookup(indexer)
@@ -428,7 +428,9 @@ def set_values(self, indexer, value):
428428

429429
indices = np.insert(indices, pos, indexer)
430430
sp_values = np.insert(self.sp_values, pos, value)
431-
sp_index = _make_index(self.sp_index.length, indices, self.kind)
431+
# Length can be increased when adding a new value into index
432+
length = max(self.sp_index.length, indexer + 1)
433+
sp_index = _make_index(length, indices, self.kind)
432434

433435
return SparseArray(sp_values, sparse_index=sp_index,
434436
fill_value=self.fill_value)

pandas/core/sparse/series.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -530,25 +530,16 @@ def set_value(self, label, value, takeable=False):
530530
return self._set_value(label, value, takeable=takeable)
531531

532532
def _set_value(self, label, value, takeable=False):
533-
self._data = self._data.copy().setitem(indexer=label, value=value)
533+
self._data = self._data.copy()
534+
try:
535+
idx = self.index.get_loc(label)
536+
except KeyError:
537+
idx = len(self)
538+
self._data.axes[0] = self._data.index.append(Index([label]))
539+
self._data = self._data.setitem(indexer=idx, value=value)
534540
return self
535541
_set_value.__doc__ = set_value.__doc__
536542

537-
def _set_values(self, key, value):
538-
539-
# this might be inefficient as we have to recreate the sparse array
540-
# rather than setting individual elements, but have to convert
541-
# the passed slice/boolean that's in dense space into a sparse indexer
542-
# not sure how to do that!
543-
if isinstance(key, Series):
544-
key = key.values
545-
546-
values = self.values.to_dense()
547-
values[key] = _index.convert_scalar(values, value)
548-
values = SparseArray(values, fill_value=self.fill_value,
549-
kind=self.kind)
550-
self._data = SingleBlockManager(values, self.index)
551-
552543
def to_dense(self, sparse_only=False):
553544
"""
554545
Convert SparseSeries to a Series.

pandas/tests/sparse/test_frame.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
is_object_dtype,
1616
is_float)
1717
from pandas.core.indexes.datetimes import DatetimeIndex
18+
from pandas.errors import PerformanceWarning
1819
from pandas.tseries.offsets import BDay
1920
from pandas.util import testing as tm
2021
from pandas.compat import lrange
@@ -1398,7 +1399,7 @@ def test_numpy_func_call(self):
13981399
getattr(np, func)(self.frame)
13991400

14001401

1401-
def _test_assignment(kind, indexer, key=None):
1402+
def _test_assignment(kind, indexer, key=None, expect_warning=True):
14021403
arr = np.array([[1, nan],
14031404
[nan, 1]])
14041405
df = DataFrame(arr, copy=True)
@@ -1410,7 +1411,11 @@ def get_indexer(df):
14101411
if key is None:
14111412
key = pd.isnull(sdf).to_sparse()
14121413

1413-
get_indexer(sdf)[key] = 2
1414+
if expect_warning:
1415+
with tm.assert_produces_warning(PerformanceWarning):
1416+
get_indexer(sdf)[key] = 2
1417+
else:
1418+
get_indexer(sdf)[key] = 2
14141419

14151420
get_indexer(df)[key] = 2
14161421
res = df.to_sparse(kind=kind)
@@ -1435,12 +1440,13 @@ def test_frame_assignment_loc(spindex_kind, indexer, key):
14351440
_test_assignment(spindex_kind, indexer, key)
14361441

14371442

1438-
@pytest.mark.parametrize('key', [None, [0, 1], [True, False]])
1443+
@pytest.mark.parametrize('key', [None, [True, False]])
14391444
def test_frame_assignment_setitem(spindex_kind, key):
14401445
_test_assignment(spindex_kind, None, key)
14411446

14421447

14431448
@pytest.mark.parametrize('indexer', ['loc', 'at'])
14441449
@pytest.mark.parametrize('key', [3])
14451450
def test_frame_assignment_extend_index(spindex_kind, indexer, key):
1446-
_test_assignment(spindex_kind, indexer, key)
1451+
_test_assignment(spindex_kind, indexer, key,
1452+
expect_warning=indexer == 'at')

pandas/tests/sparse/test_series.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from pandas import (Series, DataFrame, bdate_range,
1313
isna, compat, _np_version_under1p12)
14+
from pandas.errors import PerformanceWarning
1415
from pandas.tseries.offsets import BDay
1516
import pandas.util.testing as tm
1617
from pandas.compat import range
@@ -1450,6 +1451,8 @@ def test_series_assignment(kind, indexer, key):
14501451
res = SparseSeries(res, kind=kind)
14511452

14521453
ss_setitem = getattr(ss, indexer) if indexer else ss
1453-
ss_setitem[key] = 1
1454+
1455+
with tm.assert_produces_warning(PerformanceWarning):
1456+
ss_setitem[key] = 1
14541457

14551458
tm.assert_sp_series_equal(ss, res)

0 commit comments

Comments
 (0)