如何在Pandas多层行索引DataFrame中删除含指定词的行?
Got it, let's break this down. Using xs and drop can feel clunky here because they're better suited for exact index matches or selecting full levels—not fuzzy substring checks across multiple levels. Boolean indexing is the way to go here, and it works seamlessly for multiple target keywords too.
Step 1: Create a Sample Multi-Index DataFrame
First, let's set up a test DataFrame to work with (you can swap this out for your actual data):
import pandas as pd # Build a multi-index DataFrame with level names index = pd.MultiIndex.from_tuples( [ ("the fox", "quick"), ("brown dog", "fox jumps"), ("lazy over", "dog"), ("cat", "over the"), ("brown bear", "quick dog") # This row has no target keywords ], names=["level_1", "level_2"] ) df = pd.DataFrame({"value": [1, 2, 3, 4, 5]}, index=index)
Step 2: Define Target Keywords and Build the Filter Mask
We'll create a boolean mask that flags any row where either level 1 or level 2 contains any of your target words. Then we'll invert this mask to keep only the rows we want.
# List of target words to match targets = ["fox", "over"] # Combine targets into a regex pattern (matches any of the words) pattern = "|".join(targets) # Create mask: True if level_1 OR level_2 contains any target word mask = ( df.index.get_level_values("level_1").str.contains(pattern, case=False) | df.index.get_level_values("level_2").str.contains(pattern, case=False) ) # Invert the mask to keep rows that DON'T match any target new_df = df[~mask]
Running this will leave you with only the row ("brown bear", "quick dog") in new_df—exactly the rows that don't have "fox" or "over" in either index level.
Step 3: Reusable Function (Optional)
If you need to do this often, wrap the logic into a function for flexibility (you can specify which levels to check, toggle case sensitivity, etc.):
def filter_multiindex_rows(df, check_levels, target_words, case_sensitive=False): """ Remove rows from a multi-index DataFrame where specified levels contain target substrings. Args: df: Input DataFrame with multi-level row index check_levels: List of index levels to check (names or positions, e.g., ["level_1", 1]) target_words: List of substrings to match for removal case_sensitive: Whether to respect case in matches (default: False) Returns: Filtered DataFrame with no matching rows """ match_pattern = "|".join(target_words) filter_mask = pd.Series([False] * len(df), index=df.index) for level in check_levels: filter_mask |= df.index.get_level_values(level).str.contains( match_pattern, case=case_sensitive ) return df[~filter_mask] # Usage example: Check both levels for "fox" and "over" filtered_df = filter_multiindex_rows( df=df, check_levels=["level_1", "level_2"], target_words=["fox", "over"] )
Why This Works Better Than xs/drop
xsis designed for exact matches or selecting entire slices of an index level, not fuzzy substring checks.- Using
dropwould require first collecting all index tuples that match your criteria, which adds extra steps. Boolean indexing lets you filter in one clean step without manually tracking index values.
内容的提问来源于stack exchange,提问作者sshussain270

