Repository: alteryx/woodwork
Pull request #1600 (2022-12-14 20:07:31)

Remove int from boolean predict

codecov[bot]: # [Codecov](https://codecov.io/gh/alteryx/woodwork/pull/1600?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx) Report
> Merging [#1600](https://codecov.io/gh/alteryx/woodwork/pull/1600?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx) (747691e) into [main](https://codecov.io/gh/alteryx/woodwork/commit/3e2366c3b8fb1669c3247879f78cefaa8883dbca?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx) (3e2366c) will **decrease** coverage by `81.14%`.
> The diff coverage is `n/a`.

```diff
@@             Coverage Diff             @@
##             main    #1600       +/-   ##
===========================================
- Coverage   98.77%   17.62%   -81.15%     
===========================================
  Files          98       98               
  Lines       11545    11540        -5     
===========================================
- Hits        11403     2034     -9369     
- Misses        142     9506     +9364     
```


| [Impacted Files](https://codecov.io/gh/alteryx/woodwork/pull/1600?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx) | Coverage Δ | |
|---|---|---|
| [woodwork/config.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvY29uZmlnLnB5) | `53.33% <ø> (-46.67%)` | :arrow_down: |
| [woodwork/logical\_types.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvbG9naWNhbF90eXBlcy5weQ==) | `45.30% <ø> (-54.70%)` | :arrow_down: |
| [woodwork/tests/logical\_types/test\_logical\_types.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvdGVzdHMvbG9naWNhbF90eXBlcy90ZXN0X2xvZ2ljYWxfdHlwZXMucHk=) | `0.00% <ø> (-100.00%)` | :arrow_down: |
| [woodwork/tests/type\_system/conftest.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvdGVzdHMvdHlwZV9zeXN0ZW0vY29uZnRlc3QucHk=) | `0.00% <ø> (-100.00%)` | :arrow_down: |
| [woodwork/type\_sys/inference\_functions.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvdHlwZV9zeXMvaW5mZXJlbmNlX2Z1bmN0aW9ucy5weQ==) | `30.27% <ø> (-69.73%)` | :arrow_down: |
| [woodwork/tests/test\_config.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvdGVzdHMvdGVzdF9jb25maWcucHk=) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [woodwork/tests/test\_version.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvdGVzdHMvdGVzdF92ZXJzaW9uLnB5) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [woodwork/tests/utils/test\_utils.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvdGVzdHMvdXRpbHMvdGVzdF91dGlscy5weQ==) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [woodwork/tests/utils/test\_concat.py](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx#diff-d29vZHdvcmsvdGVzdHMvdXRpbHMvdGVzdF9jb25jYXQucHk=) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| ... and [64 more](https://codecov.io/gh/alteryx/woodwork/pull/1600/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alteryx)


Patch:
diff --git a/docs/source/release_notes.rst b/docs/source/release_notes.rst
index 99a849a..a70d050 100644
--- a/docs/source/release_notes.rst
+++ b/docs/source/release_notes.rst
@@ -11,6 +11,7 @@ Future Release
         * Schema now maintains column order after renaming a column (:pr:`1594`)
     * Changes
         * Rename `backup_dtype` to `pyspark_dtype` (:pr:`1593`)
+        * Removed inference for `["0", "1"]`, `["0.0", "1.0"]`, and `[0, 1]` as Boolean logical types, but maintained forced inference of such values (:pr:`1600`)
     * Documentation Changes
     * Testing Changes
 
diff --git a/woodwork/config.py b/woodwork/config.py
index 3583c8c..405ef14 100644
--- a/woodwork/config.py
+++ b/woodwork/config.py
@@ -56,12 +56,12 @@ CONFIG_DEFAULTS = {
     "boolean_inference_strings": [
         ["yes", "no"],
         ["y", "n"],
-        ["1", "0"],
-        ["1.0", "0.0"],
         ["true", "false"],
         ["t", "f"],
     ],
-    "boolean_inference_ints": [1, 0],
+    # when adding to boolean_inference_ints, add `0, 1` to the list directly
+    # rather than making it nested lists
+    "boolean_inference_ints": [],
 }
 
 
diff --git a/woodwork/logical_types.py b/woodwork/logical_types.py
index d8e3ef2..f70ea63 100644
--- a/woodwork/logical_types.py
+++ b/woodwork/logical_types.py
@@ -968,7 +968,7 @@ def _coerce_boolean(series, null_invalid_values=False):
 
 def _transform_boolean(series, null_invalid_values):
     boolean_inference_list = config.get_option("boolean_inference_strings")
-    boolean_inference_list.append(config.get_option("boolean_inference_ints"))
+    boolean_inference_list.extend([["1", "0"], ["1.0", "0.0"]])
     valid = {}
     for booleans in boolean_inference_list:
         valid[booleans[0]] = True
diff --git a/woodwork/type_sys/inference_functions.py b/woodwork/type_sys/inference_functions.py
index 63043bf..cce2285 100644
--- a/woodwork/type_sys/inference_functions.py
+++ b/woodwork/type_sys/inference_functions.py
@@ -110,7 +110,9 @@ def boolean_nullable_func(series):
                 return True
         except TypeError:  # Necessary to check for non-hashable values because of object dtype consideration
             return False
-    elif pdtypes.is_integer_dtype(series.dtype):
+    elif pdtypes.is_integer_dtype(series.dtype) and len(
+        config.get_option("boolean_inference_ints"),
+    ):
         series_unique = set(series)
         if series_unique == set(config.get_option("boolean_inference_ints")):
             return True


Test patch:
diff --git a/woodwork/tests/logical_types/test_logical_types.py b/woodwork/tests/logical_types/test_logical_types.py
index d3e952f..fbc9cf5 100644
--- a/woodwork/tests/logical_types/test_logical_types.py
+++ b/woodwork/tests/logical_types/test_logical_types.py
@@ -6,6 +6,7 @@ import pandas as pd
 import pytest
 
 from woodwork.accessor_utils import _is_dask_series, _is_spark_series, init_series
+from woodwork.config import config
 from woodwork.exceptions import (
     TypeConversionError,
     TypeConversionWarning,
@@ -938,13 +939,10 @@ def test_datetime_pivot_point_no_format_provided():
 def test_boolean_other_values(df_type):
     df = pd.DataFrame(
         {
-            "bool1": [0, 1, 0, 1, 1, 0],
             "bool2": ["t", "f", "t", "f", "t", "t"],
             "bool3": ["T", "F", "T", "F", "F", "f"],
             "bool4": ["true", "false", "false", "false", "true", "true"],
             "bool5": ["True", "False", "False", "True", "false", "TRUE"],
-            "bool6": ["1", "0", "1", "1", "1", "0"],
-            "bool7": ["1.0", "0.0", "1.0", "1.0", "1.0", "0.0"],
             "bool8": ["YES", "NO", "YES", "yes", "no", "no"],
             "bool9": ["N", "N", "n", "y", "Y", "y"],
         },
@@ -992,7 +990,6 @@ def test_boolean_cast_nulls_as():
     (
         [True, True, False, False],
         ["Yes", "yes", "NO", "no"],
-        ["1", "1", "0", "0"],
         ["True", "true", "false", "FALSE"],
     ),
 )
@@ -1027,7 +1024,6 @@ def test_boolean_nullable_other_values_dont_cast(null, df_type):
             "bool3": ["T", "F", "T", "F", "F", null],
             "bool4": ["true", "false", "false", "false", "true", null],
             "bool5": ["True", "False", "False", "True", null, "TRUE"],
-            "bool6": ["1", "0", "1", null, "1", "0"],
             "bool7": ["YES", "NO", "YES", "yes", null, "no"],
         },
     )
@@ -1060,3 +1056,53 @@ def test_boolean_mixed_string():
 
     df.ww.init()
     assert all([str(dtype) != "Boolean" for dtype in df.ww.logical_types.values()])
+
+
+@pytest.mark.parametrize("ints_to_config,type", [[False, "Integer"], [True, "Boolean"]])
+def test_boolean_int_works(ints_to_config, type):
+    df = pd.DataFrame({"ints": [i % 2 for i in range(100)]})
+    df2 = df.copy()
+
+    def tester_df_ints():
+        df.ww.init()
+        assert [str(v) for v in df.ww.logical_types.values()] == [type]
+
+        df2.ww.init(logical_types={"ints": "Boolean"})
+        assert [str(v) for v in df2.ww.logical_types.values()] == ["Boolean"]
+        assert df2.values.tolist() == [[bool(i % 2)] for i in range(100)]
+
+    if ints_to_config:
+        with config.with_options(boolean_inference_ints=[0, 1]):
+            tester_df_ints()
+    else:
+        tester_df_ints()
+
+
+def test_boolean_strings_of_numeric_work():
+    expected = {
+        "str_ints": pd.Series([True, False, False] * 10, dtype="bool"),
+        "str_floats": pd.Series([True, False, False] * 10, dtype="bool"),
+        "str_ints_nans": pd.Series([True, False, np.nan] * 10, dtype="boolean"),
+        "str_floats_nans": pd.Series([True, False, np.nan] * 10, dtype="boolean"),
+    }
+    str_ints = ["1", "0", "0"] * 10
+    str_floats = ["1.0", "0.0", "0.0"] * 10
+    str_ints_nans = ["1", "0", None] * 10
+    str_floats_nans = ["1.0", "0.0", None] * 10
+
+    df = pd.DataFrame(
+        {
+            "str_ints": str_ints,
+            "str_floats": str_floats,
+            "str_ints_nans": str_ints_nans,
+            "str_floats_nans": str_floats_nans,
+        },
+    )
+    logical_types = {
+        "str_ints": "Boolean",
+        "str_floats": "Boolean",
+        "str_ints_nans": "BooleanNullable",
+        "str_floats_nans": "BooleanNullable",
+    }
+    df.ww.init(logical_types=logical_types)
+    pd.testing.assert_frame_equal(pd.DataFrame.from_dict(expected), df)
diff --git a/woodwork/tests/type_system/conftest.py b/woodwork/tests/type_system/conftest.py
index 2059aad..55e956c 100644
--- a/woodwork/tests/type_system/conftest.py
+++ b/woodwork/tests/type_system/conftest.py
@@ -71,17 +71,14 @@ def pandas_bools():
     return [
         pd.Series([True, False, True, True]),
         pd.Series([True, np.nan, True, True]),
-        pd.Series([1, 0, 0, 1]),
         pd.Series(["y", "n", "N", "Y"]),
         pd.Series(["True", "false", "FALSE", "TRUE"]),
         pd.Series(["t", "f", "T", "T"]),
         pd.Series(["yes", "no", "NO", "Yes"]),
-        pd.Series(["1", "1", "1", "0"]),
         pd.Series(["y", "n", "N", None]),
         pd.Series(["True", "false", pd.NA, "TRUE"]),
         pd.Series(["t", "f", "T", np.nan]),
         pd.Series(["yes", "no", "NO", pd.NA]),
-        pd.Series(["1", "1", np.nan, "0"]),
     ]