Skip to content
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ type dedicated to boolean data that can hold missing values. With the default
``'bool`` data type based on a numpy bool array, the column can only hold
True or False values and not missing values. This new :class:`BooleanDtype`
can store missing values as well by keeping track of this in a separate mask.
(:issue:`29555`)
(:issue:`29555`, :issue:`30095`)

.. ipython:: python

Expand Down
14 changes: 12 additions & 2 deletions pandas/core/arrays/boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,19 @@ def coerce_to_array(values, mask=None, copy: bool = False):
if isinstance(values, np.ndarray) and values.dtype == np.bool_:
if copy:
values = values.copy()
elif isinstance(values, np.ndarray) and values.dtype in (np.int_, np.float_):
mask_values = isna(values)

values_bool = np.zeros(len(values), dtype=bool)
values_bool[~mask_values] = values[~mask_values].astype(bool)

if not np.all(
values_bool[~mask_values].astype(values.dtype) == values[~mask_values]
):
raise TypeError("Need to pass bool-like values")

values = values_bool
else:
# TODO conversion from integer/float ndarray can be done more efficiently
# (avoid roundtrip through object)
values_object = np.asarray(values, dtype=object)

inferred_dtype = lib.infer_dtype(values_object, skipna=True)
Expand Down
25 changes: 19 additions & 6 deletions pandas/tests/arrays/test_boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,24 +133,37 @@ def test_to_boolean_array_error(values):
pd.array(values, dtype="boolean")


def test_to_boolean_array_integer_like():
# integers of 0's and 1's
result = pd.array([1, 0, 1, 0], dtype="boolean")
def test_to_boolean_array_from_integer_array():
result = pd.array(np.array([1, 0, 1, 0]), dtype="boolean")
expected = pd.array([True, False, True, False], dtype="boolean")
tm.assert_extension_array_equal(result, expected)

result = pd.array(np.array([1, 0, 1, 0]), dtype="boolean")
# with missing values
result = pd.array(np.array([1, 0, 1, None]), dtype="boolean")
expected = pd.array([True, False, True, None], dtype="boolean")
tm.assert_extension_array_equal(result, expected)


def test_to_boolean_array_from_float_array():
result = pd.array(np.array([1.0, 0.0, 1.0, 0.0]), dtype="boolean")
expected = pd.array([True, False, True, False], dtype="boolean")
tm.assert_extension_array_equal(result, expected)

# with missing values
result = pd.array([1, 0, 1, None], dtype="boolean")
result = pd.array(np.array([1.0, 0.0, 1.0, np.nan]), dtype="boolean")
expected = pd.array([True, False, True, None], dtype="boolean")
tm.assert_extension_array_equal(result, expected)

result = pd.array(np.array([1.0, 0.0, 1.0, np.nan]), dtype="boolean")

def test_to_boolean_array_integer_like():
# integers of 0's and 1's
result = pd.array([1, 0, 1, 0], dtype="boolean")
expected = pd.array([True, False, True, False], dtype="boolean")
tm.assert_extension_array_equal(result, expected)

# with missing values
result = pd.array([1, 0, 1, None], dtype="boolean")
expected = pd.array([True, False, True, None], dtype="boolean")
tm.assert_extension_array_equal(result, expected)


Expand Down