Repository: modin-project/modin

Issue:
Binary operator throwing a ValueError for cases that Pandas accepts
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: macOS 10.15.3
- **Modin installed from (source or binary)**: source
- **Modin version**: 0.7.0
- **Python version**: 3.7.6
- **Exact command to reproduce**: See below

### Describe the problem

Adding a series to a dataframe throws a ValueError. The exact same case works fine in Pandas. All binary operators have this issue.

### Source code / logs

Here is the script to reproduce the issue:

```
import pandas as pd
import modin.pandas as mpd

df = pd.DataFrame({"col1": [1, 2, 3], "col2" : [4,5,6] })
s = pd.Series([1], index=['col1'])

mdf = mpd.DataFrame(df)
ms = mpd.Series(s)

print("df + s: ")
print(df + s)
print("mdf + ms: ")
print(mdf + ms)
```

Running it will hit the following assertion:

```
Traceback (most recent call last):
  File "bug.py", line 13, in <module>
    print(mdf + ms)
  File "/Users/wonchanl/Workspace/modinv/modin/pandas/dataframe.py", line 2084, in __add__
    return self.add(other, axis=axis, level=level, fill_value=fill_value)
  File "/Users/wonchanl/Workspace/modinv/modin/pandas/dataframe.py", line 480, in add
    other, axis=axis, level=level, fill_value=fill_value
  File "/Users/wonchanl/Workspace/modinv/modin/pandas/base.py", line 335, in add
    "add", other, axis=axis, level=level, fill_value=fill_value
  File "/Users/wonchanl/Workspace/modinv/modin/pandas/base.py", line 206, in _binary_op
    other = self._validate_other(other, axis, numeric_or_object_only=True)
  File "/Users/wonchanl/Workspace/modinv/modin/pandas/base.py", line 136, in _validate_other
    len(self._query_compiler.columns), len(other)
ValueError: Unable to coerce to Series, length must be 2: given 1
```

The Pandas implementation produces the following result:

```
df + s: 
   col1  col2
0   2.0   NaN
1   3.0   NaN
2   4.0   NaN
```

The problem disappears when the length of `ms` is exactly 2.


Discussion:
Thanks @magnatelee! I believe what is happening here is that the join part of the binary operation isn't handling the `Series` case properly when it needs to be applied along the columns.

Using a `DataFrame`, it works (though it doesn't apply to the whole column), so it's a matter of correctly joining the columns.

Resolving patch:
diff --git a/modin/pandas/base.py b/modin/pandas/base.py
--- a/modin/pandas/base.py
+++ b/modin/pandas/base.py
@@ -122,6 +122,8 @@ def _validate_other(
         if isinstance(other, BasePandasDataset):
             return other._query_compiler
         elif is_list_like(other):
+            if isinstance(other, pandas.Series):
+                other = other.reindex(self.axes[axis])
             if axis == 0:
                 if len(other) != len(self._query_compiler.index):
                     raise ValueError(


Test patch:
diff --git a/modin/pandas/test/test_dataframe.py b/modin/pandas/test/test_dataframe.py
--- a/modin/pandas/test/test_dataframe.py
+++ b/modin/pandas/test/test_dataframe.py
@@ -123,7 +123,7 @@ def inter_df_math_helper(self, modin_df, pandas_df, op):
             modin_result = getattr(modin_df, op)(list_test, axis=1)
             df_equals(modin_result, pandas_result)
 
-        # Test dataframe to series
+        # Test dataframe to series axis=0
         series_test_modin = modin_df[modin_df.columns[0]]
         series_test_pandas = pandas_df[pandas_df.columns[0]]
         try:
@@ -135,6 +135,30 @@ def inter_df_math_helper(self, modin_df, pandas_df, op):
             modin_result = getattr(modin_df, op)(series_test_modin, axis=0)
             df_equals(modin_result, pandas_result)
 
+        # Test dataframe to series axis=1
+        series_test_modin = modin_df.iloc[0]
+        series_test_pandas = pandas_df.iloc[0]
+        try:
+            pandas_result = getattr(pandas_df, op)(series_test_pandas, axis=1)
+        except Exception as e:
+            with pytest.raises(type(e)):
+                getattr(modin_df, op)(series_test_modin, axis=1)
+        else:
+            modin_result = getattr(modin_df, op)(series_test_modin, axis=1)
+            df_equals(modin_result, pandas_result)
+
+        # Test dataframe to series missing values
+        series_test_modin = modin_df.iloc[0, :-2]
+        series_test_pandas = pandas_df.iloc[0, :-2]
+        try:
+            pandas_result = getattr(pandas_df, op)(series_test_pandas, axis=1)
+        except Exception as e:
+            with pytest.raises(type(e)):
+                getattr(modin_df, op)(series_test_modin, axis=1)
+        else:
+            modin_result = getattr(modin_df, op)(series_test_modin, axis=1)
+            df_equals(modin_result, pandas_result)
+
         # Test dataframe to series with different index
         series_test_modin = modin_df[modin_df.columns[0]].reset_index(drop=True)
         series_test_pandas = pandas_df[pandas_df.columns[0]].reset_index(drop=True)