Skip to content

Commit 46d443f

Browse files
Backport PR #64092 on branch 3.0.x (BUG: DataFrame.loc fills b'' instead of NaN when adding new row and columns simultaneously (#58316)) (#64164)
Co-authored-by: roeimed0 <roeimed01@gmail.com>
1 parent 9d67932 commit 46d443f

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

doc/source/whatsnew/v3.0.1.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Bug fixes
3232
- Fixed a bug in the :func:`comparison_op` raising a ``TypeError`` for zerodim
3333
subclasses of ``np.ndarray`` (:issue:`63205`)
3434
- Added additional typing aliases in :py:mod:`pandas.api.typing.aliases` (:issue:`64098`)
35+
- Fixed bug in :meth:`DataFrame.loc` when setting new row and new columns simultaneously filling existing columns with ``b''`` instead of ``NaN`` (:issue:`58316`)
3536
- Fixed thread safety issues in :class:`DataFrame` internals on the free-threaded build (:issue:`63685`).
3637
- Prevent buffer overflow in :meth:`Rolling.corr` and :meth:`Rolling.cov` with variable windows when passing ``other`` with a longer index than the original window. This now raises ``ValueError`` (:issue:`62937`)
3738

pandas/core/internals/managers.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -845,16 +845,24 @@ def reindex_indexer(
845845
)
846846
)
847847
else:
848-
new_blocks = [
849-
blk.take_nd(
850-
indexer,
851-
axis=1,
852-
fill_value=(
853-
fill_value if fill_value is not None else blk.fill_value
854-
),
855-
)
856-
for blk in self.blocks
857-
]
848+
new_blocks = []
849+
for blk in self.blocks:
850+
if blk.dtype == np.void:
851+
# GH#58316: np.void placeholders cast to b'' when
852+
# reindexed; preserve np.void so _setitem_single_column
853+
# can later infer the correct dtype
854+
vals = np.empty((blk.values.shape[0], len(indexer)), dtype=np.void)
855+
new_blocks.append(NumpyBlock(vals, blk.mgr_locs, ndim=2))
856+
else:
857+
new_blocks.append(
858+
blk.take_nd(
859+
indexer,
860+
axis=1,
861+
fill_value=(
862+
fill_value if fill_value is not None else blk.fill_value
863+
),
864+
)
865+
)
858866

859867
new_axes = list(self.axes)
860868
new_axes[axis] = new_axis

pandas/tests/indexing/test_loc.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2228,6 +2228,21 @@ def test_loc_setitem_ea_not_full_column(self):
22282228
assert expected.dtypes["B"] == val.dtype
22292229
tm.assert_frame_equal(df, expected)
22302230

2231+
def test_loc_setitem_with_expansion_new_row_and_new_columns(self):
2232+
# GH#58316
2233+
df = DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
2234+
df.loc["x", ["C", "D"]] = 91
2235+
expected = DataFrame(
2236+
{
2237+
"A": [1.0, 2.0, 3.0, np.nan],
2238+
"B": [4.0, 5.0, 6.0, np.nan],
2239+
"C": [np.nan, np.nan, np.nan, 91.0],
2240+
"D": [np.nan, np.nan, np.nan, 91.0],
2241+
},
2242+
index=Index([0, 1, 2, "x"]),
2243+
)
2244+
tm.assert_frame_equal(df, expected)
2245+
22312246

22322247
class TestLocCallable:
22332248
def test_frame_loc_getitem_callable(self):

0 commit comments

Comments
 (0)