diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index 8cb4b3f24d435..ceab41ba82e5e 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -598,6 +598,7 @@ Other - Bug in :func:`infer_freq` and :meth:`DatetimeIndex.inferred_freq` with weekly frequencies and non-nanosecond resolutions (:issue:`55609`) - Bug in :meth:`DataFrame.apply` where passing ``raw=True`` ignored ``args`` passed to the applied function (:issue:`55009`) - Bug in :meth:`Dataframe.from_dict` which would always sort the rows of the created :class:`DataFrame`. (:issue:`55683`) +- Bug in ``dtype`` values inside a :class:`DataFrame` where initial provided dtype was lost when initializing empty DataFrame (:issue:`55649`) - Bug in rendering ``inf`` values inside a a :class:`DataFrame` with the ``use_inf_as_na`` option enabled (:issue:`55483`) - Bug in rendering a :class:`Series` with a :class:`MultiIndex` when one of the index level's names is 0 not having that name displayed (:issue:`55415`) - Bug in the error message when assigning an empty dataframe to a column (:issue:`55956`) diff --git a/pandas/core/internals/construction.py b/pandas/core/internals/construction.py index 57dd310f6b12c..c5a7844af29c2 100644 --- a/pandas/core/internals/construction.py +++ b/pandas/core/internals/construction.py @@ -393,8 +393,18 @@ def ndarray_to_mgr( nb = new_block_2d(values, placement=bp, refs=refs) block_values = [nb] - if len(columns) == 0: - # TODO: check len(values) == 0? + if len(columns) == 0 and dtype is not None: + obj_columns = list(values) + block_values = [ + new_block( + dtype.construct_array_type()._from_sequence(data, dtype=dtype), + BlockPlacement(slice(i, i + 1)), + ndim=2, + ) + for i, data in enumerate(obj_columns) + ] + + elif len(columns) == 0 and dtype is None: block_values = [] return create_block_manager_from_blocks( diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index c11150eb4c4d7..7061653235c95 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -1683,10 +1683,14 @@ def as_array( 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: + if len(self.blocks) == 0 and dtype is None: arr = np.empty(self.shape, dtype=float) return arr.transpose() + elif len(self.blocks) == 0 and dtype is not None: + arr = np.empty(self.shape, dtype=dtype) + return arr.transpose() + if self.is_single_block: blk = self.blocks[0] diff --git a/pandas/tests/frame/test_constructors.py b/pandas/tests/frame/test_constructors.py index 84189f8149d81..8b938a111202d 100644 --- a/pandas/tests/frame/test_constructors.py +++ b/pandas/tests/frame/test_constructors.py @@ -2759,6 +2759,12 @@ def test_frame_string_inference_block_dim(self): df = DataFrame(np.array([["hello", "goodbye"], ["hello", "Hello"]])) assert df._mgr.blocks[0].ndim == 2 + def test_frame_from_empty_array_perserving_dtype(self): + # GH#55649 + np_list = [np.int8, np.int16, np.uint16, np.uint64] + for n in np_list: + assert (np.array([], dtype=n).reshape((0, 0))).dtype == n + class TestDataFrameConstructorIndexInference: def test_frame_from_dict_of_series_overlapping_monthly_period_indexes(self):