Python Pandas:如何在字符串中搜索多值并输出至新列
Hey there! Since you're new to Python and want to extract multiple matching values from strings into separate new columns (similar to what you did with stringr in R), let me walk you through a couple of straightforward solutions that’ll get you exactly what you need—no more single-match limitations!
Key Idea
We’ll use regular expressions to find all matches in each string, then reshape those matches into distinct columns. We’ll leverage pandas (the go-to library for tabular data in Python) and the built-in re module for regex handling.
Solution 1: Using re.findall + List Comprehension
This approach gives you full control over how you handle matches, especially if you want to cap the number of output columns (like your request for up to 3 matches).
First, let’s set up some sample data and our target values:
import pandas as pd import re # Sample DataFrame with text column df = pd.DataFrame({ "text": [ "I love apple and banana", "Orange is way better than apple", "I ate banana, orange, and strawberry", "No favorite fruits here" ] }) # The values we want to search for target_values = ["apple", "banana", "orange"]
Next, build a regex pattern (we escape keywords to avoid issues with special characters, and use word boundaries \b to prevent partial matches):
# Build regex pattern: match any of our target values (case-insensitive) pattern = re.compile( r'\b(' + '|'.join(re.escape(val) for val in target_values) + r')\b', re.IGNORECASE )
Now extract all matches and split them into separate columns:
# Extract all matches for each row into a list df['matches_list'] = df['text'].apply(lambda x: pattern.findall(x)) # Split the list into up to 3 columns (adjust the number as needed) max_matches = 3 for i in range(max_matches): df[f'match_{i+1}'] = df['matches_list'].apply(lambda x: x[i] if i < len(x) else None) # Optional: Remove the intermediate list column df = df.drop('matches_list', axis=1)
The output will look like this:
| text | match_1 | match_2 | match_3 |
|---|---|---|---|
| I love apple and banana | apple | banana | None |
| Orange is way better than apple | Orange | apple | None |
| I ate banana, orange, and strawberry | banana | orange | None |
| No favorite fruits here | None | None | None |
Solution 2: Using pandas.str.extractall
This is a more "pandas-native" approach that avoids explicit loops. It extracts all matches and automatically reshapes them into columns.
Using the same sample data and target values:
import pandas as pd import re # Build the same regex pattern pattern = r'\b(' + '|'.join(re.escape(val) for val in target_values) + r')\b' # Extract all matches and unstack into columns matches_df = df['text'].str.extractall(pattern, flags=re.IGNORECASE).unstack() # Rename columns to something clean matches_df.columns = [f'match_{i+1}' for i in range(matches_df.shape[1])] # Merge the matches back into the original DataFrame df = df.join(matches_df)
This will produce the same result as Solution 1, with less manual loop code.
Quick Notes
- Remove
\bfrom the regex pattern if you want to allow partial matches (e.g., matching "app" in "apple"). - Adjust
max_matchesin Solution 1 if you need more than 3 output columns. - The
re.IGNORECASEflag makes the search case-insensitive—remove it if you need exact case matching.
内容的提问来源于stack exchange,提问作者user5431582

