Skip to content

Commit 71a3e3c

Browse files
authored
BUG: concat should keep series names unless ignore_index=True (#56365)
* Keep series names when not ignoring them * Split test into two shorter tests * whatsnew * tolist * Split test for concat on index
1 parent 23c20de commit 71a3e3c

File tree

3 files changed

+44
-14
lines changed

3 files changed

+44
-14
lines changed

doc/source/whatsnew/v2.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ Groupby/resample/rolling
661661
Reshaping
662662
^^^^^^^^^
663663
- Bug in :func:`concat` ignoring ``sort`` parameter when passed :class:`DatetimeIndex` indexes (:issue:`54769`)
664+
- Bug in :func:`concat` renaming :class:`Series` when ``ignore_index=False`` (:issue:`15047`)
664665
- Bug in :func:`merge_asof` raising ``TypeError`` when ``by`` dtype is not ``object``, ``int64``, or ``uint64`` (:issue:`22794`)
665666
- Bug in :func:`merge` returning columns in incorrect order when left and/or right is empty (:issue:`51929`)
666667
- Bug in :meth:`DataFrame.melt` where an exception was raised if ``var_name`` was not a string (:issue:`55948`)

pandas/core/reshape/concat.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ def __init__(
464464
# if we have mixed ndims, then convert to highest ndim
465465
# creating column numbers as needed
466466
if len(ndims) > 1:
467-
objs, sample = self._sanitize_mixed_ndim(objs, sample, ignore_index, axis)
467+
objs = self._sanitize_mixed_ndim(objs, sample, ignore_index, axis)
468468

469469
self.objs = objs
470470

@@ -580,7 +580,7 @@ def _sanitize_mixed_ndim(
580580
sample: Series | DataFrame,
581581
ignore_index: bool,
582582
axis: AxisInt,
583-
) -> tuple[list[Series | DataFrame], Series | DataFrame]:
583+
) -> list[Series | DataFrame]:
584584
# if we have mixed ndims, then convert to highest ndim
585585
# creating column numbers as needed
586586

@@ -601,19 +601,21 @@ def _sanitize_mixed_ndim(
601601
else:
602602
name = getattr(obj, "name", None)
603603
if ignore_index or name is None:
604-
name = current_column
605-
current_column += 1
606-
607-
# doing a row-wise concatenation so need everything
608-
# to line up
609-
if self._is_frame and axis == 1:
610-
name = 0
604+
if axis == 1:
605+
# doing a row-wise concatenation so need everything
606+
# to line up
607+
name = 0
608+
else:
609+
# doing a column-wise concatenation so need series
610+
# to have unique names
611+
name = current_column
612+
current_column += 1
611613

612614
obj = sample._constructor({name: obj}, copy=False)
613615

614616
new_objs.append(obj)
615617

616-
return new_objs, sample
618+
return new_objs
617619

618620
def get_result(self):
619621
cons: Callable[..., DataFrame | Series]

pandas/tests/reshape/concat/test_concat.py

+31-4
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,10 @@ def test_with_mixed_tuples(self, sort):
267267
# it works
268268
concat([df1, df2], sort=sort)
269269

270-
def test_concat_mixed_objs(self):
271-
# concat mixed series/frames
270+
def test_concat_mixed_objs_columns(self):
271+
# Test column-wise concat for mixed series/frames (axis=1)
272272
# G2385
273273

274-
# axis 1
275274
index = date_range("01-Jan-2013", periods=10, freq="h")
276275
arr = np.arange(10, dtype="int64")
277276
s1 = Series(arr, index=index)
@@ -324,13 +323,41 @@ def test_concat_mixed_objs(self):
324323
result = concat([s1, df, s2], axis=1, ignore_index=True)
325324
tm.assert_frame_equal(result, expected)
326325

327-
# axis 0
326+
def test_concat_mixed_objs_index(self):
327+
# Test row-wise concat for mixed series/frames with a common name
328+
# GH2385, GH15047
329+
330+
index = date_range("01-Jan-2013", periods=10, freq="h")
331+
arr = np.arange(10, dtype="int64")
332+
s1 = Series(arr, index=index)
333+
s2 = Series(arr, index=index)
334+
df = DataFrame(arr.reshape(-1, 1), index=index)
335+
328336
expected = DataFrame(
329337
np.tile(arr, 3).reshape(-1, 1), index=index.tolist() * 3, columns=[0]
330338
)
331339
result = concat([s1, df, s2])
332340
tm.assert_frame_equal(result, expected)
333341

342+
def test_concat_mixed_objs_index_names(self):
343+
# Test row-wise concat for mixed series/frames with distinct names
344+
# GH2385, GH15047
345+
346+
index = date_range("01-Jan-2013", periods=10, freq="h")
347+
arr = np.arange(10, dtype="int64")
348+
s1 = Series(arr, index=index, name="foo")
349+
s2 = Series(arr, index=index, name="bar")
350+
df = DataFrame(arr.reshape(-1, 1), index=index)
351+
352+
expected = DataFrame(
353+
np.kron(np.where(np.identity(3) == 1, 1, np.nan), arr).T,
354+
index=index.tolist() * 3,
355+
columns=["foo", 0, "bar"],
356+
)
357+
result = concat([s1, df, s2])
358+
tm.assert_frame_equal(result, expected)
359+
360+
# Rename all series to 0 when ignore_index=True
334361
expected = DataFrame(np.tile(arr, 3).reshape(-1, 1), columns=[0])
335362
result = concat([s1, df, s2], ignore_index=True)
336363
tm.assert_frame_equal(result, expected)

0 commit comments

Comments
 (0)