Skip to content

Commit caa242a

Browse files
committed
BUG: improper handling of mis-matched columns in DataFrame.combine, GH #529
1 parent b3829f4 commit caa242a

File tree

5 files changed

+59
-25
lines changed

5 files changed

+59
-25
lines changed

RELEASE.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pandas 0.6.2
8181
- Handle rows skipped at beginning of file in read_* functions (GH #505)
8282
- Handle improper dtype casting in ``set_value`` methods
8383
- Unary '-' / __neg__ operator on DataFrame was returning integer values
84+
- Unbox 0-dim ndarrays from certain operators like all, any in Series
8485

8586
Thanks
8687
------

pandas/core/frame.py

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,7 +1999,7 @@ def combine(self, other, func, fill_value=None):
19991999
if not self:
20002000
return other.copy()
20012001

2002-
this, other = self.align(other, axis=0, copy=False)
2002+
this, other = self.align(other, copy=False)
20032003
new_index = this.index
20042004

20052005
# sorts if possible
@@ -2008,30 +2008,24 @@ def combine(self, other, func, fill_value=None):
20082008

20092009
result = {}
20102010
for col in new_columns:
2011-
if col in this and col in other:
2012-
series = this[col].values
2013-
otherSeries = other[col].values
2014-
2015-
if do_fill:
2016-
this_mask = isnull(series)
2017-
other_mask = isnull(otherSeries)
2018-
series = series.copy()
2019-
otherSeries = otherSeries.copy()
2020-
series[this_mask] = fill_value
2021-
otherSeries[other_mask] = fill_value
2022-
2023-
arr = func(series, otherSeries)
2024-
2025-
if do_fill:
2026-
arr = com.ensure_float(arr)
2027-
arr[this_mask & other_mask] = nan
2028-
2029-
result[col] = arr
2030-
2031-
elif col in this:
2032-
result[col] = this[col]
2033-
elif col in other:
2034-
result[col] = other[col]
2011+
series = this[col].values
2012+
otherSeries = other[col].values
2013+
2014+
if do_fill:
2015+
this_mask = isnull(series)
2016+
other_mask = isnull(otherSeries)
2017+
series = series.copy()
2018+
otherSeries = otherSeries.copy()
2019+
series[this_mask] = fill_value
2020+
otherSeries[other_mask] = fill_value
2021+
2022+
arr = func(series, otherSeries)
2023+
2024+
if do_fill:
2025+
arr = com.ensure_float(arr)
2026+
arr[this_mask & other_mask] = nan
2027+
2028+
result[col] = arr
20352029

20362030
return self._constructor(result, index=new_index, columns=new_columns)
20372031

pandas/core/series.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,16 @@ def f(self, other, fill_value=None):
8888
f.__name__ = name
8989
return f
9090

91+
def _unbox(func):
92+
def f(self, *args, **kwargs):
93+
result = func(self, *args, **kwargs)
94+
if isinstance(result, np.ndarray) and result.ndim == 0:
95+
return result.item()
96+
return result
97+
f.__doc__ = func.__doc__
98+
f.__name__ = func.__name__
99+
return f
100+
91101
_stat_doc = """
92102
Return %(name)s of values
93103
%(na_action)s
@@ -566,6 +576,12 @@ def iteritems(self):
566576
__rdiv__ = _arith_method(lambda x, y: y / x, '__div__')
567577
__idiv__ = __div__
568578

579+
#----------------------------------------------------------------------
580+
# unbox reductions
581+
582+
all = _unbox(np.ndarray.all)
583+
any = _unbox(np.ndarray.any)
584+
569585
#----------------------------------------------------------------------
570586
# Misc public methods
571587

pandas/tests/test_frame.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3307,6 +3307,22 @@ def test_combineMult(self):
33073307
comb = self.empty.combineMult(self.frame)
33083308
assert_frame_equal(comb, self.frame)
33093309

3310+
def test_combine_generic(self):
3311+
df1 = self.frame
3312+
df2 = self.frame.ix[:-5, ['A', 'B', 'C']]
3313+
3314+
combined = df1.combine(df2, np.add)
3315+
combined2 = df2.combine(df1, np.add)
3316+
self.assert_(combined['D'].isnull().all())
3317+
self.assert_(combined2['D'].isnull().all())
3318+
3319+
chunk = combined.ix[:-5, ['A', 'B', 'C']]
3320+
chunk2 = combined2.ix[:-5, ['A', 'B', 'C']]
3321+
3322+
exp = self.frame.ix[:-5, ['A', 'B', 'C']].reindex_like(chunk) * 2
3323+
assert_frame_equal(chunk, exp)
3324+
assert_frame_equal(chunk2, exp)
3325+
33103326
def test_clip(self):
33113327
median = self.frame.median().median()
33123328

pandas/tests/test_series.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,13 @@ def test_append(self):
711711

712712
self.assertRaises(Exception, self.ts.append, self.ts)
713713

714+
def test_all_any(self):
715+
np.random.seed(12345)
716+
ts = tm.makeTimeSeries()
717+
bool_series = ts > 0
718+
self.assert_(not bool_series.all())
719+
self.assert_(bool_series.any())
720+
714721
def test_operators(self):
715722
series = self.ts
716723
other = self.ts[::2]

0 commit comments

Comments
 (0)