diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index e5f50bb35d6bd..9763d6664cd3b 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -1689,17 +1689,29 @@ def as_array( ------- arr : ndarray """ + passed_nan = lib.is_float(na_value) and isna(na_value) + # TODO(CoW) handle case where resulting array is a view if len(self.blocks) == 0: arr = np.empty(self.shape, dtype=float) return arr.transpose() - # We want to copy when na_value is provided to avoid - # mutating the original object - copy = copy or na_value is not lib.no_default - if self.is_single_block: blk = self.blocks[0] + + if na_value is not lib.no_default: + # We want to copy when na_value is provided to avoid + # mutating the original object + if ( + isinstance(blk.dtype, np.dtype) + and blk.dtype.kind == "f" + and passed_nan + ): + # We are already numpy-float and na_value=np.nan + pass + else: + copy = True + if blk.is_extension: # Avoid implicit conversion of extension blocks to object @@ -1712,7 +1724,8 @@ def as_array( else: arr = np.asarray(blk.get_values()) if dtype: - arr = arr.astype(dtype, copy=False) + arr = arr.astype(dtype, copy=copy) + copy = False if copy: arr = arr.copy() @@ -1724,7 +1737,11 @@ def as_array( # The underlying data was copied within _interleave, so no need # to further copy if copy=True or setting na_value - if na_value is not lib.no_default: + if na_value is lib.no_default: + pass + elif arr.dtype.kind == "f" and passed_nan: + pass + else: arr[isna(arr)] = na_value return arr.transpose() diff --git a/pandas/tests/frame/methods/test_to_numpy.py b/pandas/tests/frame/methods/test_to_numpy.py index 532f7c87557c8..20e2a63cc793c 100644 --- a/pandas/tests/frame/methods/test_to_numpy.py +++ b/pandas/tests/frame/methods/test_to_numpy.py @@ -30,6 +30,10 @@ def test_to_numpy_copy(self): assert df.to_numpy(copy=False).base is arr assert df.to_numpy(copy=True).base is not arr + # we still don't want a copy when na_value=np.nan is passed, + # and that can be respected because we are already numpy-float + assert df.to_numpy(copy=False, na_value=np.nan).base is arr + def test_to_numpy_mixed_dtype_to_str(self): # https://github.com/pandas-dev/pandas/issues/35455 df = DataFrame([[Timestamp("2020-01-01 00:00:00"), 100.0]])