Skip to content

Commit 243f688

Browse files
committed
fixup
1 parent 0f2fd56 commit 243f688

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
@@ -1760,16 +1760,15 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0,
17601760
"""
17611761
inplace = validate_bool_kwarg(inplace, 'inplace')
17621762

1763-
# use block's copy logic.
1763+
new_values, _, new, _ = self._try_coerce_args(self.values, new)
17641764
# .values may be an Index which does shallow copy by default
1765-
new_values = self.values if inplace else self.copy().values
1766-
new_values, _, new, _ = self._try_coerce_args(new_values, new)
1765+
if not inplace:
1766+
new_values = new_values.copy(deep=True)
17671767

1768-
# Cannot modify a SparseArray
17691768
if is_sparse(new_values):
1770-
new_values = new_values.to_dense()
1771-
if is_sparse(mask):
1772-
mask = mask.to_dense()
1769+
indexer = mask.to_dense().values.ravel().nonzero()[0]
1770+
block = self.copy().setitem(indexer, new)
1771+
return [block]
17731772

17741773
if isinstance(new, np.ndarray) and len(new) == len(mask):
17751774
new = new[mask]
@@ -2817,7 +2816,10 @@ def _can_hold_element(self, element):
28172816
return np.can_cast(np.asarray(element).dtype, self.sp_values.dtype)
28182817

28192818
def _try_coerce_result(self, result):
2820-
if np.ndim(result) > 0 and not is_sparse(result):
2819+
if (
2820+
# isinstance(result, np.ndarray) and
2821+
np.ndim(result) > 0
2822+
and not is_sparse(result)):
28212823
result = SparseArray(result, kind=self.kind,
28222824
fill_value=self.fill_value, dtype=self.dtype)
28232825
return result
@@ -3819,7 +3821,8 @@ def fast_xs(self, loc):
38193821
# Such assignment may incorrectly coerce NaT to None
38203822
# result[blk.mgr_locs] = blk._slice((slice(None), loc))
38213823
for i, rl in enumerate(blk.mgr_locs):
3822-
result[rl] = blk._try_coerce_result(blk.iget((i, loc)))
3824+
# result[rl] = blk._try_coerce_result(blk.iget((i, loc)))
3825+
result[rl] = blk.iget((i, loc))
38233826

38243827
return result
38253828

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
@@ -531,25 +531,16 @@ def set_value(self, label, value, takeable=False):
531531
return self._set_value(label, value, takeable=takeable)
532532

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

538-
def _set_values(self, key, value):
539-
540-
# this might be inefficient as we have to recreate the sparse array
541-
# rather than setting individual elements, but have to convert
542-
# the passed slice/boolean that's in dense space into a sparse indexer
543-
# not sure how to do that!
544-
if isinstance(key, Series):
545-
key = key.values
546-
547-
values = self.values.to_dense()
548-
values[key] = _index.convert_scalar(values, value)
549-
values = SparseArray(values, fill_value=self.fill_value,
550-
kind=self.kind)
551-
self._data = SingleBlockManager(values, self.index)
552-
553544
def to_dense(self, sparse_only=False):
554545
"""
555546
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
@@ -1534,7 +1535,7 @@ def test_quantile_multi(self):
15341535
tm.assert_sp_frame_equal(result, sparse_expected)
15351536

15361537

1537-
def _test_assignment(kind, indexer, key=None):
1538+
def _test_assignment(kind, indexer, key=None, expect_warning=True):
15381539
arr = np.array([[1, nan],
15391540
[nan, 1]])
15401541
df = DataFrame(arr, copy=True)
@@ -1546,7 +1547,11 @@ def get_indexer(df):
15461547
if key is None:
15471548
key = pd.isnull(sdf).to_sparse()
15481549

1549-
get_indexer(sdf)[key] = 2
1550+
if expect_warning:
1551+
with tm.assert_produces_warning(PerformanceWarning):
1552+
get_indexer(sdf)[key] = 2
1553+
else:
1554+
get_indexer(sdf)[key] = 2
15501555

15511556
get_indexer(df)[key] = 2
15521557
res = df.to_sparse(kind=kind)
@@ -1571,12 +1576,13 @@ def test_frame_assignment_loc(spindex_kind, indexer, key):
15711576
_test_assignment(spindex_kind, indexer, key)
15721577

15731578

1574-
@pytest.mark.parametrize('key', [None, [0, 1], [True, False]])
1579+
@pytest.mark.parametrize('key', [None, [True, False]])
15751580
def test_frame_assignment_setitem(spindex_kind, key):
15761581
_test_assignment(spindex_kind, None, key)
15771582

15781583

15791584
@pytest.mark.parametrize('indexer', ['loc', 'at'])
15801585
@pytest.mark.parametrize('key', [3])
15811586
def test_frame_assignment_extend_index(spindex_kind, indexer, key):
1582-
_test_assignment(spindex_kind, indexer, key)
1587+
_test_assignment(spindex_kind, indexer, key,
1588+
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
@@ -1557,6 +1558,8 @@ def test_series_assignment(kind, indexer, key):
15571558
res = SparseSeries(res, kind=kind)
15581559

15591560
ss_setitem = getattr(ss, indexer) if indexer else ss
1560-
ss_setitem[key] = 1
1561+
1562+
with tm.assert_produces_warning(PerformanceWarning):
1563+
ss_setitem[key] = 1
15611564

15621565
tm.assert_sp_series_equal(ss, res)

0 commit comments

Comments
 (0)