Repository: Lightning-Universe/lightning-flash

Issue:
Make categorical_input/numerical_input optional for TabularData.from_df
## 🐛 Bug
If I have only numerical features then I still have to pass an empty list for the categorical_input. It can be optional.
![image](https://user-images.githubusercontent.com/21018714/107743211-7ac00c00-6d36-11eb-918f-631e20c822ec.png)

### To Reproduce

Steps to reproduce the behavior:

1. df = pd.DataFrame({'digit': [1,2,3], 'odd_even':[0,1,0]})
2. datamodule = TabularData.from_df(df, 'odd_even', 
                    numerical_input=['digit'],
                   )

```
TypeError                                 Traceback (most recent call last)
<ipython-input-122-405a8bb49976> in <module>
      1 datamodule = TabularData.from_df(final_data, 'target', 
----> 2                     numerical_input=train_x.columns.tolist(),
      3 #                     categorical_input=[],
      4                    )

TypeError: from_df() missing 1 required positional argument: 'categorical_input'
```

#### Code sample
```
df = pd.DataFrame({'digit': [1,2,3], 'odd_even':[0,1,0]})
datamodule = TabularData.from_df(df, 'odd_even', 
                    numerical_input=['digit'],
                   )
```

### Expected behaviour
If only one of categorical or numerical input is passed then users should not be forced to enter an empty list.

### Environment

 - PyTorch Version (e.g., 1.0): '1.7.1'
 - OS (e.g., Linux): MacOS
 - How you installed PyTorch (`conda`, `pip`, source): pip
 - Python version:Python 3.7.9


> I would love to start my contribution to Flash by fixing this issue.


Discussion:

Resolving patch:
diff --git a/flash/tabular/classification/data/data.py b/flash/tabular/classification/data/data.py
--- a/flash/tabular/classification/data/data.py
+++ b/flash/tabular/classification/data/data.py
@@ -71,9 +71,9 @@ class TabularData(DataModule):
     def __init__(
         self,
         train_df: DataFrame,
-        categorical_input: List,
-        numerical_input: List,
         target: str,
+        categorical_input: Optional[List] = None,
+        numerical_input: Optional[List] = None,
         valid_df: Optional[DataFrame] = None,
         test_df: Optional[DataFrame] = None,
         batch_size: int = 2,
@@ -82,6 +82,12 @@ def __init__(
         dfs = [train_df]
         self._test_df = None
 
+        if categorical_input is None and numerical_input is None:
+            raise RuntimeError('Both `categorical_input` and `numerical_input` are None!')
+
+        categorical_input = categorical_input if categorical_input is not None else []
+        numerical_input = numerical_input if numerical_input is not None else []
+
         if valid_df is not None:
             dfs.append(valid_df)
 
@@ -133,8 +139,8 @@ def from_df(
         cls,
         train_df: DataFrame,
         target: str,
-        categorical_input: List,
-        numerical_input: List,
+        categorical_input: Optional[List] = None,
+        numerical_input: Optional[List] = None,
         valid_df: Optional[DataFrame] = None,
         test_df: Optional[DataFrame] = None,
         batch_size: int = 8,
@@ -194,8 +200,8 @@ def from_csv(
         cls,
         train_csv: str,
         target: str,
-        categorical_input: List,
-        numerical_input: List,
+        categorical_input: Optional[List] = None,
+        numerical_input: Optional[List] = None,
         valid_csv: Optional[str] = None,
         test_csv: Optional[str] = None,
         batch_size: int = 8,


Test patch:
diff --git a/tests/tabular/data/test_data.py b/tests/tabular/data/test_data.py
--- a/tests/tabular/data/test_data.py
+++ b/tests/tabular/data/test_data.py
@@ -16,6 +16,7 @@
 
 import numpy as np
 import pandas as pd
+import pytest
 
 from flash.tabular import TabularData
 from flash.tabular.classification.data.dataset import _categorize, _normalize
@@ -169,3 +170,11 @@ def test_from_csv(tmpdir):
         assert cat.shape == (1, 1)
         assert num.shape == (1, 2)
         assert target.shape == (1, )
+
+
+def test_empty_inputs():
+    train_df = TEST_DF_1.copy()
+    with pytest.raises(RuntimeError):
+        TabularData.from_df(
+            train_df, categorical_input=None, numerical_input=None, target="label", num_workers=0, batch_size=1
+        )