Skip to content

Commit 3a2fe0b

Browse files
committed
Merge pull request #4515 from jreback/partial_setting
ENH/API: GH2578, allow ix and friends to partially set when the key is not contained in the object
2 parents f373864 + 00b6c89 commit 3a2fe0b

13 files changed

+531
-73
lines changed

doc/source/indexing.rst

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,41 @@ Pandas will detect this and raise ``IndexError``, rather than return an empty st
412412
>>> df.iloc[:,3:6]
413413
IndexError: out-of-bounds on slice (end)
414414

415+
.. _indexing.basics.partial_setting:
416+
417+
Setting With Enlargement
418+
~~~~~~~~~~~~~~~~~~~~~~~~
419+
420+
.. versionadded:: 0.13
421+
422+
The ``.loc/.ix/[]`` operations can perform enlargement when setting a non-existant key for that axis.
423+
424+
In the ``Series`` case this is effectively an appending operation
425+
426+
.. ipython:: python
427+
428+
se = Series([1,2,3])
429+
se
430+
se[5] = 5.
431+
se
432+
433+
A ``DataFrame`` can be enlarged on either axis via ``.loc``
434+
435+
.. ipython:: python
436+
437+
dfi = DataFrame(np.arange(6).reshape(3,2),
438+
columns=['A','B'])
439+
dfi
440+
dfi.loc[:,'C'] = dfi.loc[:,'A']
441+
dfi
442+
443+
This is like an ``append`` operation on the ``DataFrame``.
444+
445+
.. ipython:: python
446+
447+
dfi.loc[3] = 5
448+
dfi
449+
415450
.. _indexing.basics.get_value:
416451

417452
Fast scalar value getting and setting
@@ -431,15 +466,20 @@ Similary to ``loc``, ``at`` provides **label** based scalar lookups, while, ``ia
431466
df.at[dates[5], 'A']
432467
df.iat[3, 0]
433468
434-
You can also set using these same indexers. These have the additional
435-
capability of enlarging an object. This method *always* returns a reference to
436-
the object it modified, which in the case of enlargement, will be a **new object**:
469+
You can also set using these same indexers.
437470

438471
.. ipython:: python
439472
440473
df.at[dates[5], 'E'] = 7
441474
df.iat[3, 0] = 7
442475
476+
``at`` may enlarge the object in-place as above if the indexer is missing.
477+
478+
.. ipython:: python
479+
480+
df.at[6, 0] = 7
481+
df
482+
443483
Boolean indexing
444484
~~~~~~~~~~~~~~~~
445485

doc/source/release.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ pandas 0.13
9292
an alias of iteritems used to get around ``2to3``'s changes).
9393
(:issue:`4384`, :issue:`4375`, :issue:`4372`)
9494
- ``Series.get`` with negative indexers now returns the same as ``[]`` (:issue:`4390`)
95+
- allow ``ix/loc`` for Series/DataFrame/Panel to set on any axis even when the single-key is not currently contained in
96+
the index for that axis (:issue:`2578`)
97+
- ``at`` now will enlarge the object inplace (and return the same) (:issue:`2578`)
9598

9699
- ``HDFStore``
97100

@@ -296,7 +299,7 @@ See :ref:`Internal Refactoring<whatsnew_0130.refactoring>`
296299
- ``tslib.get_period_field()`` and ``tslib.get_period_field_arr()`` now raise
297300
if code argument out of range (:issue:`4519`, :issue:`4520`)
298301
- Fix boolean indexing on an empty series loses index names (:issue:`4235`),
299-
infer_dtype works with empty arrays.
302+
infer_dtype works with empty arrays.
300303
- Fix reindexing with multiple axes; if an axes match was not replacing the current axes, leading
301304
to a possible lazay frequency inference issue (:issue:`3317`)
302305
- Fixed issue where ``DataFrame.apply`` was reraising exceptions incorrectly

doc/source/v0.13.0.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,54 @@ API changes
134134
df1 and df2
135135
s1 and s2
136136

137+
Indexing API Changes
138+
~~~~~~~~~~~~~~~~~~~~
139+
140+
Prior to 0.13, it was impossible to use an indexer (``.loc/.iloc/.ix``) to set a value that
141+
was not contained in the index of a particular axis. (:issue:`2578`). See more at :ref:`here<indexing.basics.partial_setting>`
142+
143+
In the ``Series`` case this is effectively an appending operation
144+
145+
.. ipython:: python
146+
147+
s = Series([1,2,3])
148+
s
149+
s[5] = 5.
150+
s
151+
152+
.. ipython:: python
153+
154+
dfi = DataFrame(np.arange(6).reshape(3,2),
155+
columns=['A','B'])
156+
dfi
157+
158+
This would previously ``KeyError``
159+
160+
.. ipython:: python
161+
162+
dfi.loc[:,'C'] = dfi.loc[:,'A']
163+
dfi
164+
165+
This is like an ``append`` operation.
166+
167+
.. ipython:: python
168+
169+
dfi.loc[3] = 5
170+
dfi
171+
172+
A Panel setting operation on an arbitrary axis aligns the input to the Panel
173+
174+
.. ipython:: python
175+
176+
p = pd.Panel(np.arange(16).reshape(2,4,2),
177+
items=['Item1','Item2'],
178+
major_axis=pd.date_range('2001/1/12',periods=4),
179+
minor_axis=['A','B'],dtype='float64')
180+
p
181+
p.loc[:,:,'C'] = Series([30,32],index=p.items)
182+
p
183+
p.loc[:,:,'C']
184+
137185
Enhancements
138186
~~~~~~~~~~~~
139187

pandas/core/frame.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,18 +1731,12 @@ def set_value(self, index, col, value):
17311731
engine.set_value(series.values, index, value)
17321732
return self
17331733
except KeyError:
1734-
new_index, new_columns = self._expand_axes((index, col))
1735-
result = self.reindex(index=new_index, columns=new_columns,
1736-
copy=False)
1737-
likely_dtype, value = _infer_dtype_from_scalar(value)
17381734

1739-
made_bigger = not np.array_equal(new_columns, self.columns)
1735+
# set using a non-recursive method & reset the cache
1736+
self.loc[index,col] = value
1737+
self._item_cache.pop(col,None)
17401738

1741-
# how to make this logic simpler?
1742-
if made_bigger:
1743-
com._possibly_cast_item(result, col, likely_dtype)
1744-
1745-
return result.set_value(index, col, value)
1739+
return self
17461740

17471741
def irow(self, i, copy=False):
17481742
return self._ixs(i, axis=0)

0 commit comments

Comments
 (0)