Skip to content

Commit 41b3f9c

Browse files
committed
ENH: add Series/DataFrame.update methods and rst docs, close #961
1 parent e8fc1c0 commit 41b3f9c

File tree

6 files changed

+89
-0
lines changed

6 files changed

+89
-0
lines changed

RELEASE.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pandas 0.8.0
6565
- Fix label slicing issues with float index values (#1167)
6666
- Fix segfault caused by empty groups passed to groupby (#1048)
6767
- Fix occasionally misbehaved reindexing in the presence of NaN labels (#522)
68+
- Fix imprecise logic causing weird Series results from .apply (#1183)
6869

6970
pandas 0.7.3
7071
============

doc/source/merging.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
import numpy as np
88
np.random.seed(123456)
9+
from numpy import nan
910
from pandas import *
1011
randn = np.random.randn
1112
np.set_printoptions(precision=4, suppress=True)
@@ -552,3 +553,33 @@ them together on their indexes. The same is true for ``Panel.join``.
552553
df1
553554
df1.join([df2, df3])
554555
556+
.. _merging.multiple_join:
557+
558+
Merging together values within Series or DataFrame columns
559+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
560+
561+
Another fairly common situation is to have two like-indexed (or similarly
562+
indexed) Series or DataFrame objects and wanting to "patch" values in one
563+
object from values for matching indices in the other. Here is an example:
564+
565+
.. ipython:: python
566+
567+
df1 = DataFrame([[nan, 3., 5.], [-4.6, np.nan, nan],
568+
[nan, 7., nan]])
569+
df2 = DataFrame([[-42.6, np.nan, -8.2], [-5., 1.6, 4]],
570+
index=[1, 2])
571+
572+
For this, use the ``combine_first`` method:
573+
574+
.. ipython:: python
575+
576+
df1.combine_first(df2)
577+
578+
Note that this method only takes values from the right DataFrame if they are
579+
missing in the left DataFrame. A related method, ``update``, alters non-NA
580+
values inplace:
581+
582+
.. ipython:: python
583+
584+
df1.update(df2)
585+
df1

pandas/core/frame.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,6 +2781,25 @@ def combine_first(self, other):
27812781
combiner = lambda x, y: np.where(isnull(x), y, x)
27822782
return self.combine(other, combiner)
27832783

2784+
def update(self, other, join='left'):
2785+
"""
2786+
Modify DataFrame in place using non-NA values from passed
2787+
DataFrame. Aligns on indices
2788+
2789+
Parameters
2790+
----------
2791+
other : DataFrame
2792+
join : {'left', 'right', 'outer', 'inner'}, default 'left'
2793+
"""
2794+
if join != 'left':
2795+
raise NotImplementedError
2796+
2797+
other = other.reindex_like(self)
2798+
for col in self.columns:
2799+
this = self[col].values
2800+
that = other[col].values
2801+
self[col] = np.where(isnull(that), this, that)
2802+
27842803
#----------------------------------------------------------------------
27852804
# Misc methods
27862805

pandas/core/series.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,19 @@ def combine_first(self, other):
15591559
return Series(np.where(isnull(this), other, this), index=new_index,
15601560
name=name)
15611561

1562+
def update(self, other):
1563+
"""
1564+
Modify Series in place using non-NA values from passed
1565+
Series. Aligns on index
1566+
1567+
Parameters
1568+
----------
1569+
other : Series
1570+
"""
1571+
other = other.reindex_like(self)
1572+
mask = notnull(other)
1573+
np.putmask(self.values, mask, other.values)
1574+
15621575
#----------------------------------------------------------------------
15631576
# Reindexing, sorting
15641577

pandas/tests/test_frame.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4316,6 +4316,23 @@ def test_combine_first_mixed_bug(self):
43164316
combined = frame1.combine_first(frame2)
43174317
self.assertEqual(len(combined.columns), 5)
43184318

4319+
def test_update(self):
4320+
df = DataFrame([[1.5, nan, 3.],
4321+
[1.5, nan, 3.],
4322+
[1.5, nan, 3],
4323+
[1.5, nan, 3]])
4324+
4325+
other = DataFrame([[3.6, 2., np.nan],
4326+
[np.nan, np.nan, 7]], index=[1, 3])
4327+
4328+
df.update(other)
4329+
4330+
expected = DataFrame([[1.5, nan, 3],
4331+
[3.6, 2, 3],
4332+
[1.5, nan, 3],
4333+
[1.5, nan, 7.]])
4334+
assert_frame_equal(df, expected)
4335+
43194336
def test_combineAdd(self):
43204337
# trivial
43214338
comb = self.frame.combineAdd(self.frame)

pandas/tests/test_series.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,6 +1527,14 @@ def test_combine_first(self):
15271527
result = s.combine_first(Series([], index=[]))
15281528
assert_series_equal(s, result)
15291529

1530+
def test_update(self):
1531+
s = Series([1.5, nan, 3., 4., nan])
1532+
s2 = Series([nan, 3.5, nan, 5.])
1533+
s.update(s2)
1534+
1535+
expected = Series([1.5, 3.5, 3., 5., np.nan])
1536+
assert_series_equal(s, expected)
1537+
15301538
def test_corr(self):
15311539
import scipy.stats as stats
15321540

0 commit comments

Comments
 (0)