Repository: modin-project/modin

Issue:
`reset_index` doesn't work well in case of MultiIndex columns with OmniSci backend
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: Any
- **Modin version** (`modin.__version__`): 8d1790cab1985e15868d77ae0471bd35e0bfcd6c
- **Python version**: 3.7.5
- **Code we can use to reproduce**: 
```python
import modin.pandas as pd
from modin.pandas.test.utils import df_equals
import pandas

data = {("a", "i"): [1, 2, 3], ("b", "j"): [3, 4, 5]}
index = pd.Index([0, 1, 2], name="index")

md_df = pd.DataFrame(data, index=index)
pd_df = pandas.DataFrame(data, index=index)

md_res = md_df.reset_index(drop=False)
pd_res = pd_df.reset_index(drop=False)

try:
    df_equals(md_res, pd_res)
except AssertionError as e:
    print(e)

print(f"\nModin dtypes:\n{md_res.dtypes}")
print(f"\nModin' index dtype:\n{md_res.dtypes['index']}") # Series instead of actual dtype
```

<details><summary>Output</summary>

```
DataFrame.columns are different

DataFrame.columns levels are different
[left]:  1, Index(['index', ('a', 'i'), ('b', 'j')], dtype='object')
[right]: 2, MultiIndex([('index',  ''),
            (    'a', 'i'),
            (    'b', 'j')],
           )

Modin dtypes:
index         int64
dtype: object
(a, i)                      int64
(b, j)                      int64
dtype: object

Modin' index dtype:
    int64
dtype: object
```

</details>

<!--
You can obtain the Modin version with

python -c "import modin; print(modin.__version__)"
-->

### Describe the problem
When doing `reset_index` on the frame with MultiIndex columns, OmniSci backend produces frame with incorrect columns and inconsistent dtypes.



Discussion:

Resolving patch:
diff --git a/modin/experimental/engines/omnisci_on_ray/frame/data.py b/modin/experimental/engines/omnisci_on_ray/frame/data.py
--- a/modin/experimental/engines/omnisci_on_ray/frame/data.py
+++ b/modin/experimental/engines/omnisci_on_ray/frame/data.py
@@ -146,8 +146,8 @@ def id_str(self):
     def get_dtype(self, col):
         # If we search for an index column type in a MultiIndex then we need to
         # extend index column names to tuples.
-        if isinstance(self._dtypes, MultiIndex) and not isinstance(col, tuple):
-            return self._dtypes[(col, *([""] * (self._dtypes.nlevels - 1)))]
+        if isinstance(self._dtypes.index, MultiIndex) and not isinstance(col, tuple):
+            return self._dtypes[(col, *([""] * (self._dtypes.index.nlevels - 1)))]
         return self._dtypes[col]
 
     def ref(self, col):
@@ -1231,12 +1231,21 @@ def reset_index(self, drop):
                     name = f"level_{i}"
                 if name in exprs:
                     raise ValueError(f"cannot insert {name}, already exists")
+                if isinstance(self.columns, MultiIndex) and not isinstance(name, tuple):
+                    name = (name, *([""] * (self.columns.nlevels - 1)))
                 exprs[name] = self.ref(c)
             for c in self.columns:
                 if c in exprs:
                     raise ValueError(f"cannot insert {c}, already exists")
                 exprs[c] = self.ref(c)
-            new_columns = Index.__new__(Index, data=exprs.keys(), dtype="O")
+            new_columns = Index.__new__(
+                Index,
+                data=exprs.keys(),
+                dtype="O",
+                name=self.columns.names
+                if isinstance(self.columns, MultiIndex)
+                else self.columns.name,
+            )
             return self.__constructor__(
                 columns=new_columns,
                 dtypes=self._dtypes_for_exprs(exprs),


Test patch:
diff --git a/modin/experimental/engines/omnisci_on_ray/test/test_dataframe.py b/modin/experimental/engines/omnisci_on_ray/test/test_dataframe.py
--- a/modin/experimental/engines/omnisci_on_ray/test/test_dataframe.py
+++ b/modin/experimental/engines/omnisci_on_ray/test/test_dataframe.py
@@ -462,6 +462,34 @@ def applier(lib):
 
         eval_general(pd, pandas, applier)
 
+    @pytest.mark.parametrize("is_multiindex", [True, False])
+    @pytest.mark.parametrize(
+        "column_names", [None, ["level1", None], ["level1", "level2"]]
+    )
+    def test_reset_index_multicolumns(self, is_multiindex, column_names):
+        index = (
+            pandas.MultiIndex.from_tuples(
+                [(i, j, k) for i in range(2) for j in range(3) for k in range(4)],
+                names=["l1", "l2", "l3"],
+            )
+            if is_multiindex
+            else pandas.Index(np.arange(len(self.data["a"])), name="index")
+        )
+        columns = pandas.MultiIndex.from_tuples(
+            [("a", "b"), ("b", "c")], names=column_names
+        )
+        data = np.array(list(self.data.values())).T
+
+        def applier(df, **kwargs):
+            df = df + 1
+            return df.reset_index(drop=False)
+
+        run_and_compare(
+            fn=applier,
+            data=data,
+            constructor_kwargs={"index": index, "columns": columns},
+        )
+
     def test_set_index_name(self):
         index = pandas.Index.__new__(pandas.Index, data=[i for i in range(24)])