Repository: dask/dask

Issue:
Series comparison fill_value not supported
Currently dask Series comparison operation methods (e.g. `.eq()`, `.lt()`, etc) don't support the `fill_value` keyword like pandas Series do. For example, 

```python
import numpy as np
import pandas as pd
import dask.dataframe as dd

s = pd.Series([1, 2, 4, np.nan, 7, 2])
s_nan = pd.Series([1, 2, 4, 5, 7, 2])

ds = dd.from_pandas(s, npartitions=3)
ds_nan = dd.from_pandas(s_nan, npartitions=3)

eq_pd = s.eq(s_nan, fill_value=4)
print(f'eq_pd = {eq_pd}')

eq_dd = ds.eq(ds_nan, fill_value=4)
print(f'eq_dd = {eq_dd}')
```

throws an unexpected keyword error:

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-1-18b77b3714d3> in <module>()
     14 print(f'eq_pd = {eq_pd}')
     15
---> 16 eq_dd = ds.eq(ds_nan, fill_value=4)
     17 print(f'eq_dd = {eq_dd}')

TypeError: meth() got an unexpected keyword argument 'fill_value'
```



Discussion:

Resolving patch:
diff --git a/dask/dataframe/core.py b/dask/dataframe/core.py
--- a/dask/dataframe/core.py
+++ b/dask/dataframe/core.py
@@ -2170,7 +2170,7 @@ def to_string(self, max_rows=5):
 
     @classmethod
     def _bind_operator_method(cls, name, op):
-        """ bind operator method like DataFrame.add to this class """
+        """ bind operator method like Series.add to this class """
 
         def meth(self, other, level=None, fill_value=None, axis=0):
             if level is not None:
@@ -2184,13 +2184,17 @@ def meth(self, other, level=None, fill_value=None, axis=0):
 
     @classmethod
     def _bind_comparison_method(cls, name, comparison):
-        """ bind comparison method like DataFrame.add to this class """
+        """ bind comparison method like Series.eq to this class """
 
-        def meth(self, other, level=None, axis=0):
+        def meth(self, other, level=None, fill_value=None, axis=0):
             if level is not None:
                 raise NotImplementedError('level must be None')
             axis = self._validate_axis(axis)
-            return elemwise(comparison, self, other, axis=axis)
+            if fill_value is None:
+                return elemwise(comparison, self, other, axis=axis)
+            else:
+                op = partial(comparison, fill_value=fill_value)
+                return elemwise(op, self, other, axis=axis)
 
         meth.__doc__ = comparison.__doc__
         bind_method(cls, name, meth)
@@ -2917,7 +2921,7 @@ def meth(self, other, axis='columns', level=None, fill_value=None):
 
     @classmethod
     def _bind_comparison_method(cls, name, comparison):
-        """ bind comparison method like DataFrame.add to this class """
+        """ bind comparison method like DataFrame.eq to this class """
 
         def meth(self, other, axis='columns', level=None):
             if level is not None:


Test patch:
diff --git a/dask/dataframe/tests/test_arithmetics_reduction.py b/dask/dataframe/tests/test_arithmetics_reduction.py
--- a/dask/dataframe/tests/test_arithmetics_reduction.py
+++ b/dask/dataframe/tests/test_arithmetics_reduction.py
@@ -1070,3 +1070,17 @@ def test_reductions_frame_nan(split_every):
                   ddf.sem(axis=1, skipna=False, ddof=0, split_every=split_every))
         assert_eq(df.mean(axis=1, skipna=False),
                   ddf.mean(axis=1, skipna=False, split_every=split_every))
+
+
+@pytest.mark.parametrize('comparison', ['lt', 'gt', 'le', 'ge', 'ne', 'eq'])
+def test_series_comparison_nan(comparison):
+    s = pd.Series([1, 2, 3, 4, 5, 6, 7])
+    s_nan = pd.Series([1, -1, 8, np.nan, 5, 6, 2.4])
+    ds = dd.from_pandas(s, 3)
+    ds_nan = dd.from_pandas(s_nan, 3)
+
+    fill_value = 7
+    comparison_pd = getattr(s, comparison)
+    comparison_dd = getattr(ds, comparison)
+    assert_eq(comparison_dd(ds_nan, fill_value=fill_value),
+              comparison_pd(s_nan, fill_value=fill_value))