Take a repeated lead-in off the front of every value, and nothing else.
What it does
Why does every label in the column start with the same eight characters? Because whoever built the table put the category in the row name: HURRICANE KATRINA, Noise - Residential, Total nonfarm employment, or a survey question repeated in full ahead of each of its answers. The prefix carried information once. In a chart legend it is just eight characters of noise, repeated forty times.
.str.removeprefix() removes one occurrence of a literal string from the front of each value, and if the value does not start with that string it hands it back unchanged. It is str.removesuffix at the other end, with the same single argument and the same guarantee, and it pairs naturally with str.startswith: select the rows that have the prefix, then take it off.
Official documentation: Series.str.removeprefix
A worked example, on real data
FEMA publishes every disaster it has ever declared:
import pandas as pd
url = ('https://www.fema.gov/api/open/v2/DisasterDeclarationsSummaries.csv'
'?$select=disasterNumber,state,declarationTitle,incidentType,fyDeclared'
'&$top=100000')
df = pd.read_csv(url)
df['declarationTitle'].value_counts().head(6)
declarationTitle
COVID-19 PANDEMIC 4165
SEVERE STORMS AND FLOODING 3961
SEVERE WINTER STORM 3692
COVID-19 3692
SEVERE STORMS & FLOODING 3387
HURRICANE KATRINA EVACUATION 2602
Name: count, dtype: int64
70,248 declarations and 2,485 distinct titles. The hurricanes are the ones with a redundant prefix, so I select them the way this method is nearly always paired — with str.startswith:
hurricanes = df.loc[df['declarationTitle'].str.startswith('HURRICANE '),
'declarationTitle']
hurricanes.value_counts().head(6)
declarationTitle
HURRICANE KATRINA EVACUATION 2602
HURRICANE IRMA 663
HURRICANE RITA 637
HURRICANE SANDY 559
HURRICANE HELENE 548
HURRICANE IRENE 498
Name: count, dtype: int64
12,943 rows, every one of them starting with the same ten characters. I want the storm names:
hurricanes.str.removeprefix('HURRICANE ').value_counts().head(6)
declarationTitle
KATRINA EVACUATION 2602
IRMA 663
RITA 637
SANDY 559
HELENE 548
IRENE 498
Name: count, dtype: int64
Now the version people reach for first:
hurricanes.str.strip('HURRICANE ').value_counts().head(6)
declarationTitle
KATRINA EVACUATIO 2602
M 861
841
L 808
T 712
SANDY 559
Name: count, dtype: int64
861 declarations are now called M, and 841 are called nothing at all. HURRICANE HELENE came out as L. strip was handed the set {'H','U','R','I','C','A','N','E',' '} and ate inward from both ends until it found a character outside it, which for a storm named out of the same alphabet is most of the name.
The damage is not confined to the hurricanes, either. strip runs on every row, so it goes after the wildfires too:
titles = df['declarationTitle'].drop_duplicates()
(pd.DataFrame({'title': titles, 'strip': titles.str.strip('HURRICANE ')})
.loc[lambda df_: (df_['title'] != df_['strip'])
& ~df_['title'].str.startswith('HURRICANE ')]
.head(4)
.reset_index(drop=True))
title strip
0 MUKLUK FIRE MUKLUK F
1 FIELDER MOUNTAIN FIRE FIELDER MOUNTAIN F
2 TRAIN TRESTLE FIRE TRAIN TRESTLE F
3 STALLION FIRE STALLION F
Counted across the distinct titles: removeprefix left 2,367 of 2,485 untouched, which is exactly the 118 hurricane titles changed and nothing else. strip left 717.
That "untouched" number is the feature, not a happy accident. It is why REMNANTS OF HURRICANE HELENE survives this call intact — it contains the prefix but does not start with it, and removeprefix is anchored.
Two mistakes people make
Using a regexp because the prefix looks harmless. The three prefixes in the Bamboo Weekly archive are '$', 'A.D. ' and a sentence ending in a colon. Every one of them is a trap as a pattern: $ means end-of-string, and the dots in A.D. match any character. removeprefix has nothing to escape and no regex= argument to forget.
Trimming before you have selected. Removing a prefix is safe on rows that do not have it, so it is tempting to skip the filter. Sometimes that is right — above, I wanted the wildfires kept as they were. But when the prefix is what identifies the rows you care about, select on it first with str.startswith, or you will quietly carry along rows that were never part of the question.
Where it shows up in Bamboo Weekly
Three Bamboo Weekly solutions use .str.removeprefix().
Bamboo Weekly #143: Phones in school is the canonical pairing, and the reason to learn both methods together. Every row of a survey repeats the question in full — 'How much have students at your school been impacted by cell phone usage in: ' — so the chain assigns that string to a variable, selects with .str.startswith(question_start) and trims with .str.removeprefix(question_start) in the very next line. It is also where I explained why these methods exist at all: they were added to Python "in no small part because people were mistakenly using str.strip, and getting surprised by the results."
Bamboo Weekly #168: US gas prices is the currency case, applied across a whole data frame at once: .apply(lambda s_: s_.str.removeprefix('$').astype(float)). I had originally written that with a regular expression, "but this was much simpler."
Bamboo Weekly #165: Artemis II uses it to make a timestamp parseable. NASA's Horizons service prefixes every date it returns with A.D., and .str.strip().str.removeprefix('A.D. ') clears the way for to_datetime with format='%Y-%b-%d %H:%M:%S.%f'. If you would rather not memorize which of those is the month and which the minute, I like strfti.me — it shows the result as you type.
Practice it
Work through a .str.removeprefix() exercise, with instant feedback and no signup required: practice.lernerpython.com/bamboo-weekly/str-removeprefix/
Go deeper
The two methods on either side of this one are str.startswith, for finding the rows that carry the prefix, and str.removesuffix, for the same job at the end of the string. When what you want gone really is a set of characters — leading periods, mixed whitespace, stray punctuation — then str.strip is the right method, and that page shows the cases where its set behavior is exactly what you want.
If the lead-in varies from row to row, neither of these will help: str.split on the delimiter, or str.replace with an anchored pattern, is the next step.
More Pandas videos on Python and Pandas with Reuven Lerner.
Bamboo Weekly is the practice. If you want the structured version — full courses with downloadable Jupyter notebooks, plus live Pandas office hours when you get stuck — that is LernerPython+Data. A paid Bamboo Weekly subscription is included with it.
Related methods
.str.startswith()— which is how you find the rows carrying a prefix in the first place.str.strip()— which strips a character set from both ends, and is not this
See it on real data
Below are the 3 Bamboo Weekly exercises that use str.removeprefix on real-world data — try each one, then study the worked solution.
Part of the Pandas Methods Index. See also practice by skill.