Skip to content

Commit 5302d1b

Browse files
authored
BUG: FloatingArray(float16data) (#44715)
1 parent 3e7c2f6 commit 5302d1b

File tree

7 files changed

+67
-1
lines changed

7 files changed

+67
-1
lines changed

doc/source/whatsnew/v1.4.0.rst

+2
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,8 @@ ExtensionArray
812812
- Avoid raising ``PerformanceWarning`` about fragmented DataFrame when using many columns with an extension dtype (:issue:`44098`)
813813
- Bug in :class:`IntegerArray` and :class:`FloatingArray` construction incorrectly coercing mismatched NA values (e.g. ``np.timedelta64("NaT")``) to numeric NA (:issue:`44514`)
814814
- Bug in :meth:`BooleanArray.__eq__` and :meth:`BooleanArray.__ne__` raising ``TypeError`` on comparison with an incompatible type (like a string). This caused :meth:`DataFrame.replace` to sometimes raise a ``TypeError`` if a nullable boolean column was included (:issue:`44499`)
815+
- Bug in :func:`array` incorrectly raising when passed a ``ndarray`` with ``float16`` dtype (:issue:`44715`)
816+
- Bug in calling ``np.sqrt`` on :class:`BooleanArray` returning a malformed :class:`FloatingArray` (:issue:`44715`)
815817
- Bug in :meth:`Series.where` with ``ExtensionDtype`` when ``other`` is a NA scalar incompatible with the series dtype (e.g. ``NaT`` with a numeric dtype) incorrectly casting to a compatible NA value (:issue:`44697`)
816818
-
817819

pandas/core/arrays/floating.py

+4
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ def __init__(self, values: np.ndarray, mask: np.ndarray, copy: bool = False):
254254
"values should be floating numpy array. Use "
255255
"the 'pd.array' function instead"
256256
)
257+
if values.dtype == np.float16:
258+
# If we don't raise here, then accessing self.dtype would raise
259+
raise TypeError("FloatingArray does not support np.float16 dtype.")
260+
257261
super().__init__(values, mask, copy=copy)
258262

259263
@classmethod

pandas/core/arrays/masked.py

+4
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,10 @@ def reconstruct(x):
466466
return IntegerArray(x, m)
467467
elif is_float_dtype(x.dtype):
468468
m = mask.copy()
469+
if x.dtype == np.float16:
470+
# reached in e.g. np.sqrt on BooleanArray
471+
# we don't support float16
472+
x = x.astype(np.float32)
469473
return FloatingArray(x, m)
470474
else:
471475
x[mask] = np.nan

pandas/core/construction.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,12 @@ def array(
353353
elif inferred_dtype == "integer":
354354
return IntegerArray._from_sequence(data, copy=copy)
355355

356-
elif inferred_dtype in ("floating", "mixed-integer-float"):
356+
elif (
357+
inferred_dtype in ("floating", "mixed-integer-float")
358+
and getattr(data, "dtype", None) != np.float16
359+
):
360+
# GH#44715 Exclude np.float16 bc FloatingArray does not support it;
361+
# we will fall back to PandasArray.
357362
return FloatingArray._from_sequence(data, copy=copy)
358363

359364
elif inferred_dtype == "boolean":

pandas/tests/arrays/boolean/test_function.py

+11
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ def test_ufuncs_unary(ufunc):
6666
tm.assert_series_equal(result, expected)
6767

6868

69+
def test_ufunc_numeric():
70+
# np.sqrt on np.bool returns float16, which we upcast to Float32
71+
# bc we do not have Float16
72+
arr = pd.array([True, False, None], dtype="boolean")
73+
74+
res = np.sqrt(arr)
75+
76+
expected = pd.array([1, 0, None], dtype="Float32")
77+
tm.assert_extension_array_equal(res, expected)
78+
79+
6980
@pytest.mark.parametrize("values", [[True, False], [True, None]])
7081
def test_ufunc_reduce_raises(values):
7182
a = pd.array(values, dtype="boolean")

pandas/tests/arrays/floating/test_construction.py

+34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
import locale
2+
13
import numpy as np
24
import pytest
35

6+
from pandas.compat import (
7+
is_platform_windows,
8+
np_version_under1p19,
9+
)
10+
411
import pandas as pd
512
import pandas._testing as tm
613
from pandas.core.arrays import FloatingArray
@@ -40,6 +47,33 @@ def test_floating_array_constructor():
4047
FloatingArray(values)
4148

4249

50+
def test_floating_array_disallows_float16(request):
51+
# GH#44715
52+
arr = np.array([1, 2], dtype=np.float16)
53+
mask = np.array([False, False])
54+
55+
msg = "FloatingArray does not support np.float16 dtype"
56+
with pytest.raises(TypeError, match=msg):
57+
FloatingArray(arr, mask)
58+
59+
if not np_version_under1p19:
60+
# Troubleshoot
61+
# https://github.com/numpy/numpy/issues/20512#issuecomment-985807740
62+
lowered = np.core._type_aliases.english_lower("Float16")
63+
assert lowered == "float16", lowered
64+
65+
if np_version_under1p19 or (
66+
locale.getlocale()[0] != "en_US" and not is_platform_windows()
67+
):
68+
# the locale condition may need to be refined; this fails on
69+
# the CI in the ZH_CN build
70+
mark = pytest.mark.xfail(reason="numpy does not raise on np.dtype('Float16')")
71+
request.node.add_marker(mark)
72+
73+
with pytest.raises(TypeError, match="data type 'Float16' not understood"):
74+
pd.array([1.0, 2.0], dtype="Float16")
75+
76+
4377
def test_floating_array_constructor_copy():
4478
values = np.array([1, 2, 3, 4], dtype="float64")
4579
mask = np.array([False, False, False, True], dtype="bool")

pandas/tests/arrays/test_array.py

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@
5151
# String alias passes through to NumPy
5252
([1, 2], "float32", PandasArray(np.array([1, 2], dtype="float32"))),
5353
([1, 2], "int64", PandasArray(np.array([1, 2], dtype=np.int64))),
54+
# GH#44715 FloatingArray does not support float16, so fall back to PandasArray
55+
(
56+
np.array([1, 2], dtype=np.float16),
57+
None,
58+
PandasArray(np.array([1, 2], dtype=np.float16)),
59+
),
5460
# idempotency with e.g. pd.array(pd.array([1, 2], dtype="int64"))
5561
(
5662
PandasArray(np.array([1, 2], dtype=np.int32)),

0 commit comments

Comments
 (0)