Python循环统计文本单词出现次数性能优化求助
优化文本单词出现次数统计的性能方案
原代码循环遍历单词列表,每次对整个DataFrame的Text列调用str.count,时间复杂度为O(M*N)(M是文本行数,N是单词列表长度),重复遍历数据集导致效率极低,尤其是单词列表较长时。以下是三种高效优化方案:
方案一:正则批量匹配+分组统计
利用正则一次性匹配所有目标单词,再通过分组统计次数,避免多次遍历数据集。
import pandas as pd import re # 假设已有df和wordlist wordlist = ['i','love','David','Mary'] # 统一大小写,避免大小写不匹配问题 wordlist_lower = [word.lower() for word in wordlist] df['Text_lower'] = df['Text'].str.lower() # 构建正则模式:匹配整个单词(若需子串匹配则去掉\b) pattern = r'\b(' + '|'.join(re.escape(word) for word in wordlist_lower) + r')\b' # 提取所有匹配的单词 matches = df['Text_lower'].str.extractall(pattern)[0] # 按原行索引和单词分组统计次数 counts = matches.groupby([matches.index.get_level_values(0), 0]).size().unstack(fill_value=0) # 合并到原DataFrame df = df.join(counts) # 可选:删除临时列 df.drop('Text_lower', axis=1, inplace=True)
说明:
\b用于匹配完整单词,避免子串误匹配(如'love'不会匹配'loved');若需统计子串出现次数,可移除\b。re.escape处理单词中的特殊字符,避免正则语法错误。
方案二:使用CountVectorizer向量化统计
借助sklearn的CountVectorizer进行批量词频统计,底层为向量化操作,效率极高。
import pandas as pd from sklearn.feature_extraction.text import CountVectorizer # 假设已有df和wordlist wordlist = ['i','love','David','Mary'] # 统一大小写 wordlist_lower = [word.lower() for word in wordlist] df['Text_lower'] = df['Text'].str.lower() # 初始化向量器,指定目标单词列表 vectorizer = CountVectorizer(vocabulary=wordlist_lower, token_pattern=r'\b\w+\b') # 转换文本得到词频矩阵 count_matrix = vectorizer.fit_transform(df['Text_lower']) # 转换为DataFrame并合并 count_df = pd.DataFrame( count_matrix.toarray(), columns=vectorizer.get_feature_names_out(), index=df.index ) df = df.join(count_df) df.drop('Text_lower', axis=1, inplace=True)
说明:
token_pattern=r'\b\w+\b'确保匹配完整单词,若需子串统计可调整或移除该参数。- 该方法适合单词列表较长的场景,性能远优于循环遍历。
方案三:拆分文本+Explode分组统计
通过拆分文本为单词列表,展开后过滤目标单词再分组计数,逻辑直观。
import pandas as pd # 假设已有df和wordlist wordlist = ['i','love','David','Mary'] # 统一大小写 wordlist_lower = [word.lower() for word in wordlist] df['Text_lower'] = df['Text'].str.lower() # 拆分文本为单词列表(按非字母字符分割) df['words'] = df['Text_lower'].str.split(r'\W+') # 展开每个单词为单独行 exploded = df.explode('words') # 过滤出目标单词 filtered = exploded[exploded['words'].isin(wordlist_lower)] # 按原行索引和单词统计次数 counts = filtered.groupby([filtered.index, 'words']).size().unstack(fill_value=0) # 合并到原DataFrame df = df.join(counts) # 删除临时列 df.drop(['Text_lower', 'words'], axis=1, inplace=True)
注意事项:
- 若文本中有连续非字母字符,
split(r'\W+')会自动处理,避免空字符串。 - 该方法内存占用略高,适合文本长度适中的场景。
内容的提问来源于stack exchange,提问作者foy
相关产品推荐
相关产品推荐

