Repository: modin-project/modin

Issue:
applymap doesn't support `na_action`
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: macOS Monterey
- **Modin version** (`modin.__version__`): 49fc2cf3733f20ac6cf8a7c61e42ef7aa5cf4b03
- **Python version**: 3.9.12
- **Code we can use to reproduce**:

```python
import modin.pandas as pd
df = pd.DataFrame([[None]])
print(df.applymap(lambda x: x + 1, na_action='ignore'))
```

### Describe the problem
pandas supports `na_action`. Modin accepts that param but ignores it.


### Source code / logs

Ray workers give stack trace:

<details>
<summary>Show stack trace</summary>

```
2022-05-27 13:10:00,001	ERROR worker.py:92 -- Unhandled error (suppress with 'RAY_IGNORE_UNHANDLED_ERRORS=1'): ray::_apply_func() (pid=16783, ip=127.0.0.1)
  File "/Users/maheshvashishtha/software_sources/modin/modin/core/execution/ray/implementations/pandas_on_ray/partitioning/partition.py", line 385, in _apply_func
    result = func(partition, *args, **kwargs)
  File "/Users/maheshvashishtha/software_sources/modin/modin/core/dataframe/algebra/map.py", line 48, in <lambda>
    lambda x: function(x, *args, **kwargs), *call_args, **call_kwds
  File "/Users/maheshvashishtha/opt/anaconda3/envs/modin-latest/lib/python3.9/site-packages/pandas/core/frame.py", line 8924, in applymap
    return self.apply(infer).__finalize__(self, "applymap")
  File "/Users/maheshvashishtha/opt/anaconda3/envs/modin-latest/lib/python3.9/site-packages/pandas/core/frame.py", line 8839, in apply
    return op.apply().__finalize__(self, method="apply")
  File "/Users/maheshvashishtha/opt/anaconda3/envs/modin-latest/lib/python3.9/site-packages/pandas/core/apply.py", line 727, in apply
    return self.apply_standard()
  File "/Users/maheshvashishtha/opt/anaconda3/envs/modin-latest/lib/python3.9/site-packages/pandas/core/apply.py", line 851, in apply_standard
    results, res_index = self.apply_series_generator()
  File "/Users/maheshvashishtha/opt/anaconda3/envs/modin-latest/lib/python3.9/site-packages/pandas/core/apply.py", line 867, in apply_series_generator
    results[i] = self.f(v)
  File "/Users/maheshvashishtha/opt/anaconda3/envs/modin-latest/lib/python3.9/site-packages/pandas/core/frame.py", line 8922, in infer
    return lib.map_infer(x.astype(object)._values, func, ignore_na=ignore_na)
  File "pandas/_libs/lib.pyx", line 2870, in pandas._libs.lib.map_infer
  File "<ipython-input-1-4deb779c1b25>", line 3, in <lambda>
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
```
</details>



Discussion:

Resolving patch:
diff --git a/modin/core/storage_formats/base/query_compiler.py b/modin/core/storage_formats/base/query_compiler.py
--- a/modin/core/storage_formats/base/query_compiler.py
+++ b/modin/core/storage_formats/base/query_compiler.py
@@ -1103,7 +1103,7 @@ def abs(self):
         """
         return DataFrameDefault.register(pandas.DataFrame.abs)(self)
 
-    def applymap(self, func):
+    def applymap(self, func, *args, **kwargs):
         """
         Apply passed function elementwise.
 
@@ -1111,13 +1111,17 @@ def applymap(self, func):
         ----------
         func : callable(scalar) -> scalar
             Function to apply to each element of the QueryCompiler.
+        *args : iterable
+        **kwargs : dict
 
         Returns
         -------
         BaseQueryCompiler
             Transformed QueryCompiler.
         """
-        return DataFrameDefault.register(pandas.DataFrame.applymap)(self, func=func)
+        return DataFrameDefault.register(pandas.DataFrame.applymap)(
+            self, func, *args, **kwargs
+        )
 
     # FIXME: `**kwargs` which follows `numpy.conj` signature was inherited
     # from ``PandasQueryCompiler``, we should get rid of this dependency.
diff --git a/modin/pandas/dataframe.py b/modin/pandas/dataframe.py
--- a/modin/pandas/dataframe.py
+++ b/modin/pandas/dataframe.py
@@ -354,7 +354,9 @@ def applymap(
         """
         if not callable(func):
             raise ValueError("'{0}' object is not callable".format(type(func)))
-        return DataFrame(query_compiler=self._query_compiler.applymap(func))
+        return DataFrame(
+            query_compiler=self._query_compiler.applymap(func, na_action, **kwargs)
+        )
 
     def apply(
         self, func, axis=0, raw=False, result_type=None, args=(), **kwargs


Test patch:
diff --git a/modin/pandas/test/dataframe/test_map_metadata.py b/modin/pandas/test/dataframe/test_map_metadata.py
--- a/modin/pandas/test/dataframe/test_map_metadata.py
+++ b/modin/pandas/test/dataframe/test_map_metadata.py
@@ -207,22 +207,17 @@ def test_add_prefix(data):
 
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)
 @pytest.mark.parametrize("testfunc", test_func_values, ids=test_func_keys)
-def test_applymap(request, data, testfunc):
-    modin_df = pd.DataFrame(data)
-    pandas_df = pandas.DataFrame(data)
+@pytest.mark.parametrize(
+    "na_action", [None, "ignore"], ids=["no_na_action", "ignore_na"]
+)
+def test_applymap(data, testfunc, na_action):
+    modin_df, pandas_df = create_test_dfs(data)
 
     with pytest.raises(ValueError):
         x = 2
         modin_df.applymap(x)
 
-    try:
-        pandas_result = pandas_df.applymap(testfunc)
-    except Exception as e:
-        with pytest.raises(type(e)):
-            modin_df.applymap(testfunc)
-    else:
-        modin_result = modin_df.applymap(testfunc)
-        df_equals(modin_result, pandas_result)
+    eval_general(modin_df, pandas_df, lambda df: df.applymap(testfunc, na_action))
 
 
 @pytest.mark.parametrize("data", test_data_values, ids=test_data_keys)