如何在Pandas DataFrame多行间搜索多短语并解决IndexError报错
IndexError Traceback (most recent call last)
1 for match in re.finditer(search, text, re.IGNORECASE):
----> 2 idx1 = df[df["start"] == match.start()].index[0]
3 idx2 = df[df["end"] == match.end()].index[0]
4 df.loc[idx1:idx2, "match"] = True
~/opt/anaconda3/lib/python3.8/site-packages/pandas/core/indexes/base.py in getitem(self, key)
4099 if is_scalar(key):
4100 key = com.cast_scalar_indexer(key, warn_float=True)
-> 4101 return getitem(key)
4102
4103 if isinstance(key, slice):
IndexError: index 0 is out of bounds for axis 0 with size 0
请问该如何修复这个报错?是否有其他方法可以实现上述需求? --- ### 报错原因 1. 代码直接覆盖了DataFrame中原有的`start`/`end`时间列,改为存储字符偏移量,一旦计算逻辑和实际匹配位置存在偏差,就会出现筛选结果为空的情况,取`index[0]`时就会触发索引越界。 2. 用完全相等的条件`df["start"] == match.start()`筛选行容错率极低,只要匹配位置因为空格、大小写等问题出现微小偏差就会找不到对应行。 ### 修复方案 首先修改字符偏移列的命名,避免覆盖原有时间字段,同时改用区间匹配定位行: ```python import re import pandas as pd # 读取搜索词 search_terms = [term.strip() for term in open("terms.txt").readlines()] search_pattern = fr"({'|'.join(search_terms)})" # 拼接所有字幕文本 full_text = " ".join(df["subtitle"]) # 计算每个subtitle对应的字符区间,不覆盖原有start/end时间列 char_length = df["subtitle"].apply(len) char_end = char_length.cumsum() + pd.RangeIndex(len(df)) # 累加值加对应空格偏移 char_start = char_end.shift(fill_value=-1) + 1 df["char_start"] = char_start df["char_end"] = char_end df["match"] = False for match in re.finditer(search_pattern, full_text, re.IGNORECASE): m_start, m_end = match.span() # 用区间匹配找对应的起止行 idx1 = df[(df["char_start"] <= m_start) & (df["char_end"] >= m_start)].index[0] idx2 = df[(df["char_start"] <= m_end) & (df["char_end"] >= m_end)].index[0] df.loc[idx1:idx2, "match"] = True
替代实现(滑动窗口法)
不需要计算字符偏移,直接根据搜索短语的词数做滑动窗口匹配,逻辑更清晰不容易出错:
import pandas as pd # 读取搜索词,统计最长短语的词数 search_terms = [term.strip() for term in open("terms.txt").readlines()] max_window = max(len(t.split()) for t in search_terms) df["match"] = False subtitle_list = df["subtitle"].str.lower().tolist() # 统一转小写做模糊匹配 for window_size in range(2, max_window+1): # 短语最少包含2个词 for i in range(len(subtitle_list) - window_size + 1): window_str = " ".join(subtitle_list[i:i+window_size]) # 检查窗口内容是否匹配任意搜索短语 if any(window_str == term.lower() for term in search_terms): # 匹配到就把窗口内所有行标为True df.loc[df.index[i]:df.index[i+window_size-1], "match"] = True
内容的提问来源于stack exchange,提问作者Regan

