diff --git a/pandas/core/arrays/arrow/array.py b/pandas/core/arrays/arrow/array.py index 08f1ffdcc6a0d..53c938faf9257 100644 --- a/pandas/core/arrays/arrow/array.py +++ b/pandas/core/arrays/arrow/array.py @@ -829,6 +829,14 @@ def __arrow_array__(self, type=None): """Convert myself to a pyarrow ChunkedArray.""" return self._pa_array + def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs): + # Need to wrap np.array results GH#62800 + result = super().__array_ufunc__(ufunc, method, *inputs, **kwargs) + if type(self) is ArrowExtensionArray: + # Exclude ArrowStringArray + return type(self)._from_sequence(result) + return result + def __array__( self, dtype: NpDtype | None = None, copy: bool | None = None ) -> np.ndarray: diff --git a/pandas/tests/extension/test_arrow.py b/pandas/tests/extension/test_arrow.py index 2aa1b658fdf7b..c1e01bbbe57a0 100644 --- a/pandas/tests/extension/test_arrow.py +++ b/pandas/tests/extension/test_arrow.py @@ -3800,3 +3800,13 @@ def test_cast_pontwise_result_decimal_nan(): pa_type = result.dtype.pyarrow_dtype assert pa.types.is_decimal(pa_type) + + +def test_ufunc_retains_missing(): + # GH#62800 + ser = pd.Series([0.1, pd.NA], dtype="float64[pyarrow]") + + result = np.sin(ser) + + expected = pd.Series([np.sin(0.1), pd.NA], dtype="float64[pyarrow]") + tm.assert_series_equal(result, expected) diff --git a/pandas/tests/series/test_npfuncs.py b/pandas/tests/series/test_npfuncs.py index b72ac8efbaa6d..f30c01b496399 100644 --- a/pandas/tests/series/test_npfuncs.py +++ b/pandas/tests/series/test_npfuncs.py @@ -43,7 +43,7 @@ def test_log_arrow_backed_missing_value(using_nan_is_na): ser = Series([1, 2, None], dtype="float64[pyarrow]") if using_nan_is_na: result = np.log(ser) - expected = np.log(Series([1, 2, None], dtype="float64")) + expected = np.log(Series([1, 2, None], dtype="float64[pyarrow]")) tm.assert_series_equal(result, expected) else: # we get cast to object which raises