Repository: pandas-dev/pandas

Issue:
bug in bool type series logical AND operation
#### Code Sample, a copy-pastable example if possible

```
s1=pd.Series([True,False,True,True])
s2=pd.Series([True,True,False])

s1.index=pd.MultiIndex.from_tuples( [(0, 2), (1, 1), (1, 2), (2, 1)],names=['st', 'at'])
s2.index=pd.Index([0,1,2], name='st')

ds1=pd.DataFrame(s1)
ds2=pd.DataFrame(s2)

s3=pd.Series([True,False,True])
s4=pd.Series([True,True,False])
```
#### Expected Output

```
st  at
0   2      True
1   1     False
1   2      True
2   1     False
dtype: bool
```

For series, `*` and `&` give different result:

```
In: s1 & s2
Out: 
st  at
0   2     False
1   1     False
1   2     False
2   1     False
dtype: bool

In: s1 * s2
Out: 
st  at
0   2      True
1   1     False
1   2      True
2   1     False
dtype: bool
```

BUT for dataframes they give the same:

```
In: ds1 * ds2
Out: 
           0
st at       
0  2    True
1  1   False
1  2    True
2  1   False

In: ds1 & ds2
Out: 
           0
st at       
0  2    True
1  1   False
1  2    True
2  1   False
```

and last for series with single index, also both `s3 & s4` or `s3 * s4` give:

```
0     True
1    False
2    False
dtype: bool
```
#### output of `pd.show_versions()`

pandas: 0.18.1



Discussion:
It seems there is going something wrong with the alignment.

Also, if you switch the position, you get an error:

```
In [43]: s2 & s1
...
ValueError: Buffer dtype mismatch, expected 'Python object' but got 'long long'
```

this is a duplicate of https://github.com/pydata/pandas/issues/1134

you need to join before you do this - it's not s well defined operation as specified 

I think it is a slightly different issue

Consider those serieses:

```
In [84]: s1 = pd.Series([True,False,True])

In [85]: s2 = pd.Series([True,True,False])

In [86]: s2b = pd.Series([True,True,False], index=[1,2,3])
```

The issue in #1134 is that the index is ignored, so using s2 or s2b gives the same:

```
In [87]: s1 == s2
Out[87]:
0     True
1    False
2    False
dtype: bool

In [88]: s1 == s2b
Out[88]:
0     True
1    False
2    False
dtype: bool
```

But in this case, s2 and s2b do not give the same:

```
In [89]: s1 & s2
Out[89]:
0     True
1    False
2    False
dtype: bool

In [90]: s1 & s2b
Out[90]:
0    False
1    False
2     True
dtype: bool
```

In the case of non-identical index, the result is also not the same as when the index is ignored:

```
In [91]: s1.values & s2b.values
Out[91]: array([ True, False, False], dtype=bool)
```


Resolving patch:
diff --git a/pandas/core/ops.py b/pandas/core/ops.py
--- a/pandas/core/ops.py
+++ b/pandas/core/ops.py
@@ -311,17 +311,6 @@ def get_op(cls, left, right, name, na_op):
         is_datetime_lhs = (is_datetime64_dtype(left) or
                            is_datetime64tz_dtype(left))
 
-        if isinstance(left, ABCSeries) and isinstance(right, ABCSeries):
-            # avoid repated alignment
-            if not left.index.equals(right.index):
-                left, right = left.align(right, copy=False)
-
-                index, lidx, ridx = left.index.join(right.index, how='outer',
-                                                    return_indexers=True)
-                # if DatetimeIndex have different tz, convert to UTC
-                left.index = index
-                right.index = index
-
         if not (is_datetime_lhs or is_timedelta_lhs):
             return _Op(left, right, name, na_op)
         else:
@@ -603,6 +592,33 @@ def _is_offset(self, arr_or_obj):
             return False
 
 
+def _align_method_SERIES(left, right, align_asobject=False):
+    """ align lhs and rhs Series """
+
+    # ToDo: Different from _align_method_FRAME, list, tuple and ndarray
+    # are not coerced here
+    # because Series has inconsistencies described in #13637
+
+    if isinstance(right, ABCSeries):
+        # avoid repeated alignment
+        if not left.index.equals(right.index):
+
+            if align_asobject:
+                # to keep original value's dtype for bool ops
+                left = left.astype(object)
+                right = right.astype(object)
+
+            left, right = left.align(right, copy=False)
+
+            index, lidx, ridx = left.index.join(right.index, how='outer',
+                                                return_indexers=True)
+            # if DatetimeIndex have different tz, convert to UTC
+            left.index = index
+            right.index = index
+
+    return left, right
+
+
 def _arith_method_SERIES(op, name, str_rep, fill_zeros=None, default_axis=None,
                          **eval_kwargs):
     """
@@ -654,6 +670,8 @@ def wrapper(left, right, name=name, na_op=na_op):
         if isinstance(right, pd.DataFrame):
             return NotImplemented
 
+        left, right = _align_method_SERIES(left, right)
+
         converted = _Op.get_op(left, right, name, na_op)
 
         left, right = converted.left, converted.right
@@ -761,8 +779,9 @@ def wrapper(self, other, axis=None):
 
         if isinstance(other, ABCSeries):
             name = _maybe_match_name(self, other)
-            if len(self) != len(other):
-                raise ValueError('Series lengths must match to compare')
+            if not self._indexed_same(other):
+                msg = 'Can only compare identically-labeled Series objects'
+                raise ValueError(msg)
             return self._constructor(na_op(self.values, other.values),
                                      index=self.index, name=name)
         elif isinstance(other, pd.DataFrame):  # pragma: no cover
@@ -784,6 +803,7 @@ def wrapper(self, other, axis=None):
 
             return self._constructor(na_op(self.values, np.asarray(other)),
                                      index=self.index).__finalize__(self)
+
         elif isinstance(other, pd.Categorical):
             if not is_categorical_dtype(self):
                 msg = ("Cannot compare a Categorical for op {op} with Series "
@@ -856,9 +876,10 @@ def wrapper(self, other):
         fill_int = lambda x: x.fillna(0)
         fill_bool = lambda x: x.fillna(False).astype(bool)
 
+        self, other = _align_method_SERIES(self, other, align_asobject=True)
+
         if isinstance(other, ABCSeries):
             name = _maybe_match_name(self, other)
-            other = other.reindex_like(self)
             is_other_int_dtype = is_integer_dtype(other.dtype)
             other = fill_int(other) if is_other_int_dtype else fill_bool(other)
 
@@ -908,7 +929,32 @@ def wrapper(self, other):
                     'floordiv': {'op': '//',
                                  'desc': 'Integer division',
                                  'reversed': False,
-                                 'reverse': 'rfloordiv'}}
+                                 'reverse': 'rfloordiv'},
+
+                    'eq': {'op': '==',
+                                 'desc': 'Equal to',
+                                 'reversed': False,
+                                 'reverse': None},
+                    'ne': {'op': '!=',
+                                 'desc': 'Not equal to',
+                                 'reversed': False,
+                                 'reverse': None},
+                    'lt': {'op': '<',
+                                 'desc': 'Less than',
+                                 'reversed': False,
+                                 'reverse': None},
+                    'le': {'op': '<=',
+                                 'desc': 'Less than or equal to',
+                                 'reversed': False,
+                                 'reverse': None},
+                    'gt': {'op': '>',
+                                 'desc': 'Greater than',
+                                 'reversed': False,
+                                 'reverse': None},
+                    'ge': {'op': '>=',
+                                 'desc': 'Greater than or equal to',
+                                 'reversed': False,
+                                 'reverse': None}}
 
 _op_names = list(_op_descriptions.keys())
 for k in _op_names:
@@ -959,10 +1005,11 @@ def _flex_method_SERIES(op, name, str_rep, default_axis=None, fill_zeros=None,
     @Appender(doc)
     def flex_wrapper(self, other, level=None, fill_value=None, axis=0):
         # validate axis
-        self._get_axis_number(axis)
+        if axis is not None:
+            self._get_axis_number(axis)
         if isinstance(other, ABCSeries):
             return self._binop(other, op, level=level, fill_value=fill_value)
-        elif isinstance(other, (np.ndarray, ABCSeries, list, tuple)):
+        elif isinstance(other, (np.ndarray, list, tuple)):
             if len(other) != len(self):
                 raise ValueError('Lengths must be equal')
             return self._binop(self._constructor(other, self.index), op,
@@ -971,7 +1018,7 @@ def flex_wrapper(self, other, level=None, fill_value=None, axis=0):
             if fill_value is not None:
                 self = self.fillna(fill_value)
 
-            return self._constructor(op(self.values, other),
+            return self._constructor(op(self, other),
                                      self.index).__finalize__(self)
 
     flex_wrapper.__name__ = name
@@ -979,7 +1026,7 @@ def flex_wrapper(self, other, level=None, fill_value=None, axis=0):
 
 
 series_flex_funcs = dict(flex_arith_method=_flex_method_SERIES,
-                         flex_comp_method=_comp_method_SERIES)
+                         flex_comp_method=_flex_method_SERIES)
 
 series_special_funcs = dict(arith_method=_arith_method_SERIES,
                             comp_method=_comp_method_SERIES,


Test patch:
diff --git a/pandas/io/tests/json/test_ujson.py b/pandas/io/tests/json/test_ujson.py
--- a/pandas/io/tests/json/test_ujson.py
+++ b/pandas/io/tests/json/test_ujson.py
@@ -1306,43 +1306,45 @@ def testSeries(self):
 
         # column indexed
         outp = Series(ujson.decode(ujson.encode(s))).sort_values()
-        self.assertTrue((s == outp).values.all())
+        exp = Series([10, 20, 30, 40, 50, 60],
+                     index=['6', '7', '8', '9', '10', '15'])
+        tm.assert_series_equal(outp, exp)
 
         outp = Series(ujson.decode(ujson.encode(s), numpy=True)).sort_values()
-        self.assertTrue((s == outp).values.all())
+        tm.assert_series_equal(outp, exp)
 
         dec = _clean_dict(ujson.decode(ujson.encode(s, orient="split")))
         outp = Series(**dec)
-        self.assertTrue((s == outp).values.all())
-        self.assertTrue(s.name == outp.name)
+        tm.assert_series_equal(outp, s)
 
         dec = _clean_dict(ujson.decode(ujson.encode(s, orient="split"),
                                        numpy=True))
         outp = Series(**dec)
-        self.assertTrue((s == outp).values.all())
-        self.assertTrue(s.name == outp.name)
 
-        outp = Series(ujson.decode(ujson.encode(
-            s, orient="records"), numpy=True))
-        self.assertTrue((s == outp).values.all())
+        outp = Series(ujson.decode(ujson.encode(s, orient="records"),
+                                   numpy=True))
+        exp = Series([10, 20, 30, 40, 50, 60])
+        tm.assert_series_equal(outp, exp)
 
         outp = Series(ujson.decode(ujson.encode(s, orient="records")))
-        self.assertTrue((s == outp).values.all())
+        tm.assert_series_equal(outp, exp)
 
-        outp = Series(ujson.decode(
-            ujson.encode(s, orient="values"), numpy=True))
-        self.assertTrue((s == outp).values.all())
+        outp = Series(ujson.decode(ujson.encode(s, orient="values"),
+                                   numpy=True))
+        tm.assert_series_equal(outp, exp)
 
         outp = Series(ujson.decode(ujson.encode(s, orient="values")))
-        self.assertTrue((s == outp).values.all())
+        tm.assert_series_equal(outp, exp)
 
         outp = Series(ujson.decode(ujson.encode(
             s, orient="index"))).sort_values()
-        self.assertTrue((s == outp).values.all())
+        exp = Series([10, 20, 30, 40, 50, 60],
+                     index=['6', '7', '8', '9', '10', '15'])
+        tm.assert_series_equal(outp, exp)
 
         outp = Series(ujson.decode(ujson.encode(
             s, orient="index"), numpy=True)).sort_values()
-        self.assertTrue((s == outp).values.all())
+        tm.assert_series_equal(outp, exp)
 
     def testSeriesNested(self):
         s = Series([10, 20, 30, 40, 50, 60], name="series",
diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py
--- a/pandas/tests/indexes/common.py
+++ b/pandas/tests/indexes/common.py
@@ -676,7 +676,8 @@ def test_equals_op(self):
             index_a == series_d
         with tm.assertRaisesRegexp(ValueError, "Lengths must match"):
             index_a == array_d
-        with tm.assertRaisesRegexp(ValueError, "Series lengths must match"):
+        msg = "Can only compare identically-labeled Series objects"
+        with tm.assertRaisesRegexp(ValueError, msg):
             series_a == series_d
         with tm.assertRaisesRegexp(ValueError, "Lengths must match"):
             series_a == array_d
diff --git a/pandas/tests/series/test_operators.py b/pandas/tests/series/test_operators.py
--- a/pandas/tests/series/test_operators.py
+++ b/pandas/tests/series/test_operators.py
@@ -43,8 +43,9 @@ def test_comparisons(self):
         s2 = Series([False, True, False])
 
         # it works!
-        s == s2
-        s2 == s
+        exp = Series([False, False, False])
+        tm.assert_series_equal(s == s2, exp)
+        tm.assert_series_equal(s2 == s, exp)
 
     def test_op_method(self):
         def check(series, other, check_reverse=False):
@@ -1080,15 +1081,15 @@ def test_comparison_label_based(self):
         a = Series([True, False, True], list('bca'))
         b = Series([False, True, False], list('abc'))
 
-        expected = Series([True, False, False], list('bca'))
+        expected = Series([False, True, False], list('abc'))
         result = a & b
         assert_series_equal(result, expected)
 
-        expected = Series([True, False, True], list('bca'))
+        expected = Series([True, True, False], list('abc'))
         result = a | b
         assert_series_equal(result, expected)
 
-        expected = Series([False, False, True], list('bca'))
+        expected = Series([True, False, False], list('abc'))
         result = a ^ b
         assert_series_equal(result, expected)
 
@@ -1096,11 +1097,11 @@ def test_comparison_label_based(self):
         a = Series([True, False, True], list('bca'))
         b = Series([False, True, False, True], list('abcd'))
 
-        expected = Series([True, False, False], list('bca'))
+        expected = Series([False, True, False, False], list('abcd'))
         result = a & b
         assert_series_equal(result, expected)
 
-        expected = Series([True, False, True], list('bca'))
+        expected = Series([True, True, False, False], list('abcd'))
         result = a | b
         assert_series_equal(result, expected)
 
@@ -1117,20 +1118,28 @@ def test_comparison_label_based(self):
 
         # vs non-matching
         result = a & Series([1], ['z'])
-        expected = Series([False, False, False], list('bca'))
+        expected = Series([False, False, False, False], list('abcz'))
         assert_series_equal(result, expected)
 
         result = a | Series([1], ['z'])
-        expected = Series([True, False, True], list('bca'))
+        expected = Series([True, True, False, False], list('abcz'))
         assert_series_equal(result, expected)
 
         # 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']),
+        for e in [Series([]), Series([1], ['z']),
                   Series(np.nan, b.index), Series(np.nan, a.index)]:
             result = a[a | e]
             assert_series_equal(result, a[a])
 
+        for e in [Series(['z'])]:
+            if compat.PY3:
+                with tm.assert_produces_warning(RuntimeWarning):
+                    result = a[a | e]
+            else:
+                result = a[a | e]
+            assert_series_equal(result, a[a])
+
         # vs scalars
         index = list('bca')
         t = Series([True, False, True])
@@ -1160,6 +1169,76 @@ def test_comparison_label_based(self):
         for v in [np.nan]:
             self.assertRaises(TypeError, lambda: t & v)
 
+    def test_comparison_flex_basic(self):
+        left = pd.Series(np.random.randn(10))
+        right = pd.Series(np.random.randn(10))
+
+        tm.assert_series_equal(left.eq(right), left == right)
+        tm.assert_series_equal(left.ne(right), left != right)
+        tm.assert_series_equal(left.le(right), left < right)
+        tm.assert_series_equal(left.lt(right), left <= right)
+        tm.assert_series_equal(left.gt(right), left > right)
+        tm.assert_series_equal(left.ge(right), left >= right)
+
+        # axis
+        for axis in [0, None, 'index']:
+            tm.assert_series_equal(left.eq(right, axis=axis), left == right)
+            tm.assert_series_equal(left.ne(right, axis=axis), left != right)
+            tm.assert_series_equal(left.le(right, axis=axis), left < right)
+            tm.assert_series_equal(left.lt(right, axis=axis), left <= right)
+            tm.assert_series_equal(left.gt(right, axis=axis), left > right)
+            tm.assert_series_equal(left.ge(right, axis=axis), left >= right)
+
+        #
+        msg = 'No axis named 1 for object type'
+        for op in ['eq', 'ne', 'le', 'le', 'gt', 'ge']:
+            with tm.assertRaisesRegexp(ValueError, msg):
+                getattr(left, op)(right, axis=1)
+
+    def test_comparison_flex_alignment(self):
+        left = Series([1, 3, 2], index=list('abc'))
+        right = Series([2, 2, 2], index=list('bcd'))
+
+        exp = pd.Series([False, False, True, False], index=list('abcd'))
+        tm.assert_series_equal(left.eq(right), exp)
+
+        exp = pd.Series([True, True, False, True], index=list('abcd'))
+        tm.assert_series_equal(left.ne(right), exp)
+
+        exp = pd.Series([False, False, True, False], index=list('abcd'))
+        tm.assert_series_equal(left.le(right), exp)
+
+        exp = pd.Series([False, False, False, False], index=list('abcd'))
+        tm.assert_series_equal(left.lt(right), exp)
+
+        exp = pd.Series([False, True, True, False], index=list('abcd'))
+        tm.assert_series_equal(left.ge(right), exp)
+
+        exp = pd.Series([False, True, False, False], index=list('abcd'))
+        tm.assert_series_equal(left.gt(right), exp)
+
+    def test_comparison_flex_alignment_fill(self):
+        left = Series([1, 3, 2], index=list('abc'))
+        right = Series([2, 2, 2], index=list('bcd'))
+
+        exp = pd.Series([False, False, True, True], index=list('abcd'))
+        tm.assert_series_equal(left.eq(right, fill_value=2), exp)
+
+        exp = pd.Series([True, True, False, False], index=list('abcd'))
+        tm.assert_series_equal(left.ne(right, fill_value=2), exp)
+
+        exp = pd.Series([False, False, True, True], index=list('abcd'))
+        tm.assert_series_equal(left.le(right, fill_value=0), exp)
+
+        exp = pd.Series([False, False, False, True], index=list('abcd'))
+        tm.assert_series_equal(left.lt(right, fill_value=0), exp)
+
+        exp = pd.Series([True, True, True, False], index=list('abcd'))
+        tm.assert_series_equal(left.ge(right, fill_value=0), exp)
+
+        exp = pd.Series([True, True, False, False], index=list('abcd'))
+        tm.assert_series_equal(left.gt(right, fill_value=0), exp)
+
     def test_operators_bitwise(self):
         # GH 9016: support bitwise op for integer types
         index = list('bca')
@@ -1195,11 +1274,11 @@ def test_operators_bitwise(self):
         s_a0b1c0 = Series([1], list('b'))
 
         res = s_tft & s_a0b1c0
-        expected = s_tff
+        expected = s_tff.reindex(list('abc'))
         assert_series_equal(res, expected)
 
         res = s_tft | s_a0b1c0
-        expected = s_tft
+        expected = s_tft.reindex(list('abc'))
         assert_series_equal(res, expected)
 
         n0 = 0
@@ -1236,9 +1315,25 @@ def test_operators_bitwise(self):
         self.assertRaises(TypeError, lambda: s_0123 & [0.1, 4, 3.14, 2])
 
         # s_0123 will be all false now because of reindexing like s_tft
-        assert_series_equal(s_tft & s_0123, Series([False] * 3, list('bca')))
+        if compat.PY3:
+            # unable to sort incompatible object via .union.
+            exp = Series([False] * 7, index=['b', 'c', 'a', 0, 1, 2, 3])
+            with tm.assert_produces_warning(RuntimeWarning):
+                assert_series_equal(s_tft & s_0123, exp)
+        else:
+            exp = Series([False] * 7, index=[0, 1, 2, 3, 'a', 'b', 'c'])
+            assert_series_equal(s_tft & s_0123, exp)
+
         # s_tft will be all false now because of reindexing like s_0123
-        assert_series_equal(s_0123 & s_tft, Series([False] * 4))
+        if compat.PY3:
+            # unable to sort incompatible object via .union.
+            exp = Series([False] * 7, index=[0, 1, 2, 3, 'b', 'c', 'a'])
+            with tm.assert_produces_warning(RuntimeWarning):
+                assert_series_equal(s_0123 & s_tft, exp)
+        else:
+            exp = Series([False] * 7, index=[0, 1, 2, 3, 'a', 'b', 'c'])
+            assert_series_equal(s_0123 & s_tft, exp)
+
         assert_series_equal(s_0123 & False, Series([False] * 4))
         assert_series_equal(s_0123 ^ False, Series([False, True, True, True]))
         assert_series_equal(s_0123 & [False], Series([False] * 4))
@@ -1322,6 +1417,123 @@ def _check_op(arr, op):
         _check_op(arr, operator.truediv)
         _check_op(arr, operator.floordiv)
 
+    def test_arith_ops_df_compat(self):
+        # GH 1134
+        s1 = pd.Series([1, 2, 3], index=list('ABC'), name='x')
+        s2 = pd.Series([2, 2, 2], index=list('ABD'), name='x')
+
+        exp = pd.Series([3.0, 4.0, np.nan, np.nan],
+                        index=list('ABCD'), name='x')
+        tm.assert_series_equal(s1 + s2, exp)
+        tm.assert_series_equal(s2 + s1, exp)
+
+        exp = pd.DataFrame({'x': [3.0, 4.0, np.nan, np.nan]},
+                           index=list('ABCD'))
+        tm.assert_frame_equal(s1.to_frame() + s2.to_frame(), exp)
+        tm.assert_frame_equal(s2.to_frame() + s1.to_frame(), exp)
+
+        # different length
+        s3 = pd.Series([1, 2, 3], index=list('ABC'), name='x')
+        s4 = pd.Series([2, 2, 2, 2], index=list('ABCD'), name='x')
+
+        exp = pd.Series([3, 4, 5, np.nan],
+                        index=list('ABCD'), name='x')
+        tm.assert_series_equal(s3 + s4, exp)
+        tm.assert_series_equal(s4 + s3, exp)
+
+        exp = pd.DataFrame({'x': [3, 4, 5, np.nan]},
+                           index=list('ABCD'))
+        tm.assert_frame_equal(s3.to_frame() + s4.to_frame(), exp)
+        tm.assert_frame_equal(s4.to_frame() + s3.to_frame(), exp)
+
+    def test_comp_ops_df_compat(self):
+        # GH 1134
+        s1 = pd.Series([1, 2, 3], index=list('ABC'), name='x')
+        s2 = pd.Series([2, 2, 2], index=list('ABD'), name='x')
+
+        s3 = pd.Series([1, 2, 3], index=list('ABC'), name='x')
+        s4 = pd.Series([2, 2, 2, 2], index=list('ABCD'), name='x')
+
+        for l, r in [(s1, s2), (s2, s1), (s3, s4), (s4, s3)]:
+
+            msg = "Can only compare identically-labeled Series objects"
+            with tm.assertRaisesRegexp(ValueError, msg):
+                l == r
+
+            with tm.assertRaisesRegexp(ValueError, msg):
+                l != r
+
+            with tm.assertRaisesRegexp(ValueError, msg):
+                l < r
+
+            msg = "Can only compare identically-labeled DataFrame objects"
+            with tm.assertRaisesRegexp(ValueError, msg):
+                l.to_frame() == r.to_frame()
+
+            with tm.assertRaisesRegexp(ValueError, msg):
+                l.to_frame() != r.to_frame()
+
+            with tm.assertRaisesRegexp(ValueError, msg):
+                l.to_frame() < r.to_frame()
+
+    def test_bool_ops_df_compat(self):
+        # GH 1134
+        s1 = pd.Series([True, False, True], index=list('ABC'), name='x')
+        s2 = pd.Series([True, True, False], index=list('ABD'), name='x')
+
+        exp = pd.Series([True, False, False, False],
+                        index=list('ABCD'), name='x')
+        tm.assert_series_equal(s1 & s2, exp)
+        tm.assert_series_equal(s2 & s1, exp)
+
+        # True | np.nan => True
+        exp = pd.Series([True, True, True, False],
+                        index=list('ABCD'), name='x')
+        tm.assert_series_equal(s1 | s2, exp)
+        # np.nan | True => np.nan, filled with False
+        exp = pd.Series([True, True, False, False],
+                        index=list('ABCD'), name='x')
+        tm.assert_series_equal(s2 | s1, exp)
+
+        # DataFrame doesn't fill nan with False
+        exp = pd.DataFrame({'x': [True, False, np.nan, np.nan]},
+                           index=list('ABCD'))
+        tm.assert_frame_equal(s1.to_frame() & s2.to_frame(), exp)
+        tm.assert_frame_equal(s2.to_frame() & s1.to_frame(), exp)
+
+        exp = pd.DataFrame({'x': [True, True, np.nan, np.nan]},
+                           index=list('ABCD'))
+        tm.assert_frame_equal(s1.to_frame() | s2.to_frame(), exp)
+        tm.assert_frame_equal(s2.to_frame() | s1.to_frame(), exp)
+
+        # different length
+        s3 = pd.Series([True, False, True], index=list('ABC'), name='x')
+        s4 = pd.Series([True, True, True, True], index=list('ABCD'), name='x')
+
+        exp = pd.Series([True, False, True, False],
+                        index=list('ABCD'), name='x')
+        tm.assert_series_equal(s3 & s4, exp)
+        tm.assert_series_equal(s4 & s3, exp)
+
+        # np.nan | True => np.nan, filled with False
+        exp = pd.Series([True, True, True, False],
+                        index=list('ABCD'), name='x')
+        tm.assert_series_equal(s3 | s4, exp)
+        # True | np.nan => True
+        exp = pd.Series([True, True, True, True],
+                        index=list('ABCD'), name='x')
+        tm.assert_series_equal(s4 | s3, exp)
+
+        exp = pd.DataFrame({'x': [True, False, True, np.nan]},
+                           index=list('ABCD'))
+        tm.assert_frame_equal(s3.to_frame() & s4.to_frame(), exp)
+        tm.assert_frame_equal(s4.to_frame() & s3.to_frame(), exp)
+
+        exp = pd.DataFrame({'x': [True, True, True, np.nan]},
+                           index=list('ABCD'))
+        tm.assert_frame_equal(s3.to_frame() | s4.to_frame(), exp)
+        tm.assert_frame_equal(s4.to_frame() | s3.to_frame(), exp)
+
     def test_series_frame_radd_bug(self):
         # GH 353
         vals = Series(tm.rands_array(5, 10))