From 5229ac675cba71378f49eaad3afb382def96dbd8 Mon Sep 17 00:00:00 2001 From: behzad nouri Date: Sun, 31 Aug 2014 18:24:05 -0400 Subject: [PATCH] BUG: consistency between logical ops & type casts --- doc/source/v0.15.0.txt | 2 +- pandas/core/ops.py | 8 +++++--- pandas/tests/test_frame.py | 2 +- pandas/tests/test_series.py | 28 ++++++++++++++++++++++++++-- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/doc/source/v0.15.0.txt b/doc/source/v0.15.0.txt index bf959141e29b2..11d248a979144 100644 --- a/doc/source/v0.15.0.txt +++ b/doc/source/v0.15.0.txt @@ -650,4 +650,4 @@ Bug Fixes - Bug in accessing groups from a ``GroupBy`` when the original grouper was a tuple (:issue:`8121`). - +- Bug in logical operations of series and their consistency with type casts (:issue:`6528`) diff --git a/pandas/core/ops.py b/pandas/core/ops.py index 7efcfb9898053..7038ee5ad0034 100644 --- a/pandas/core/ops.py +++ b/pandas/core/ops.py @@ -636,10 +636,12 @@ def wrapper(self, other): if isinstance(other, pd.Series): name = _maybe_match_name(self, other) - other = other.reindex_like(self).fillna(False).astype(bool) - return self._constructor(na_op(self.values, other.values), + left = self.astype(bool).values + right = other.astype(bool).reindex_like(self) + right = right.fillna(False).values + return self._constructor(na_op(left, right), index=self.index, - name=name).fillna(False).astype(bool) + name=name) elif isinstance(other, pd.DataFrame): return NotImplemented else: diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index f9e7cf3545374..18905ad15a31a 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -4992,7 +4992,7 @@ def test_logical_with_nas(self): # GH4947 # bool comparisons should return bool result = d['a'] | d['b'] - expected = Series([False, True]) + expected = Series(np.logical_or(d['a'], d['b']), dtype='bool') assert_series_equal(result, expected) # GH4604, automatic casting here diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 022a8b543ce32..0d78341fab330 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -2368,6 +2368,31 @@ def check(series, other, check_reverse=False): check(self.ts, 5, check_reverse=True) check(tm.makeFloatSeries(), tm.makeFloatSeries(), check_reverse=True) + def test_bool_op(self): # GH6528 & GH8151 + u = pd.Series([nan, nan, nan, False, False, True, True]) + v = pd.Series([nan, False, True, False, True, False, True]) + + for a, b in [[u, v], [v, u]]: + # against numpy logical casted to bool + assert_series_equal(a | b, Series(np.logical_or(a, b), dtype='bool')) + assert_series_equal(a & b, Series(np.logical_and(a, b), dtype='bool')) + assert_series_equal(a ^ b, # np.logical_xor throws with floats! + Series(np.logical_xor(a.values.astype(bool), + b.values.astype(bool)))) + + assert_series_equal(~ a.astype(bool), + Series(np.logical_not(a), dtype='bool')) + + # type cast semantics + assert_series_equal(a | b, a.astype(bool) | b.astype(bool)) + assert_series_equal(a & b, a.astype(bool) & b.astype(bool)) + assert_series_equal(a ^ b, a.astype(bool) ^ b.astype(bool)) + + # symmetry + assert_series_equal(a & b, b & a) + assert_series_equal(a | b, b | a) + assert_series_equal(a ^ b, b ^ a) + def test_neg(self): assert_series_equal(-self.series, -1 * self.series) @@ -3418,7 +3443,7 @@ def test_comparison_label_based(self): # identity # we would like s[s|e] == s to hold for any e, whether empty or not - for e in [Series([]),Series([1],['z']),Series(['z']),Series(np.nan,b.index),Series(np.nan,a.index)]: + for e in [Series([]),Series([1],['z']),Series(['z']),Series(False,b.index),Series(False,a.index)]: result = a[a | e] assert_series_equal(result,a[a]) @@ -6144,4 +6169,3 @@ def test_unique_data_ownership(self): if __name__ == '__main__': nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'], exit=False) -