Q&A library Python

How do I join text from several columns or rows in pandas?

Python Intermediate catconcatenationstrings

Short answer

Use the plus operator or str.cat to combine columns row by row, and str.cat with a separator to join a whole column into one string. Missing values propagate, so fill them first.

The short version

To combine columns row by row, add them with + or use str.cat. To collapse a whole column into a single string, use str.cat(sep=...). Missing values are the trap: they turn the whole combined value into NaN unless you handle them.

Combining columns row by row

import pandas as pd

df = pd.DataFrame({"first": ["Ana", "Bo"], "last": ["Smith", "Jones"]})

df["full"] = df["first"] + " " + df["last"]
print(df["full"].tolist())   # ['Ana Smith', 'Bo Jones']

Simple addition works because pandas applies it element by element to text columns.

The missing-value trap

df.loc[0, "last"] = None
df["first"] + " " + df["last"]     # ['nan', 'Bo Jones'] -> actually NaN for row 0

Adding anything to a missing value gives a missing value, so one gap poisons the whole combined string. Fill the gaps first.

df["full"] = df["first"].fillna("") + " " + df["last"].fillna("")

Or use str.cat, which takes an explicit instruction about what to do with missing values.

df["full"] = df["first"].str.cat(df["last"], sep=" ", na_rep="")

na_rep substitutes a placeholder for missing entries rather than propagating NaN, which is usually what you want and is clearer than a chain of fillna calls.

Joining a whole column into one string

pd.Series(["a", "b"]).str.cat(sep="-")   # 'a-b'

With no other column passed, str.cat collapses the Series into a single string. This is the pandas equivalent of "-".join(...), and it is useful for building a summary line or an SQL fragment.

Joining within groups

The common real need is collecting each group's values into one string.

df.groupby("city")["product"].agg(lambda s: ", ".join(s.dropna()))

The dropna() matters, because join raises on a missing value. This produces one row per city with its products listed, which is a readable summary format.

Numbers need converting first

You cannot add a number to a string. Convert explicitly.

df["label"] = df["city"] + " (" + df["amount"].astype(str) + ")"

Forgetting the astype(str) gives a TypeError, which is at least a loud failure rather than a silent one.

Prefer building strings at the end

A general point: keep numbers as numbers, dates as dates, and build display strings only at the final presentation step. Storing a combined text label in your working frame is fine, but never replace a numeric column with its formatted text version, because every subsequent calculation on it will then fail or, worse, do something strange.

Enjoying these?

Go from piecing together answers to real fluency.

Our courses take you from looking things up to doing the work with confidence, step by step on real data.

Browse the courses