[英]Python too slow to find text in string in for loop
我想提高计算文本中单词出现次数的循环性能,但现在 5 条记录大约需要 5 分钟
DataFrame
No Text
1 I love you forever...*500 other words
2 No , i know that you know xxx *100 words
我的单词表
wordlist =['i','love','David','Mary',......]
我的代码来计算单词
for i in wordlist :
df[i] = df['Text'].str.count(i)
结果:
No Text I love other_words
1 I love you ... 1 1 4
2 No, i know ... 1 0 5
您可以通过从每个Text
值中的单词创建一个Counter
,然后将其转换为列(使用pd.Series
),将wordlist
中不存在的列汇总到other_words
中,然后删除这些列来执行此操作:
import re
import pandas as pd
from collections import Counter
wordlist = list(map(str.lower, wordlist))
counters = df['Text'].apply(lambda t:Counter(re.findall(r'\b[a-z]+\b', t.lower())))
df = pd.concat([df, counters.apply(pd.Series).fillna(0).astype(int)], axis=1)
other_words = list(set(df.columns) - set(wordlist) - { 'No', 'Text' })
df['other_words'] = df[other_words].sum(axis=1)
df = df.drop(other_words, axis=1)
Output(对于您问题中的样本数据):
No Text i love other_words
0 1 I love you forever... other words 1 1 4
1 2 No , i know that you know xxx words 1 0 7
笔记:
I
和i
了。re.findall
而不是更明显的split()
以便forever...
被算作forever
而不是forever...
如果您只想计算wordlist
中的单词(而不想要other_words
计数),您可以将其简化为:
wordlist = list(map(str.lower, wordlist))
counters = df['Text'].apply(lambda t:Counter(w for w in re.findall(r'\b[a-z]+\b', t.lower()) if w in wordlist))
df = pd.concat([df, counters.apply(pd.Series).fillna(0).astype(int)], axis=1)
Output:
No Text i love
0 1 I love you forever... other words 1 1
1 2 No , i know that you know xxx words 1 0
另一种生成other_words
值的方法是生成 2 组计数器,一个是所有单词,另一个是wordlist
中的单词。 然后可以将它们相互减去以找到文本中不在单词列表中的单词数:
wordlist = list(map(str.lower, wordlist))
counters = df['Text'].apply(lambda t:Counter(w for w in re.findall(r'\b[a-z]+\b', t.lower()) if w in wordlist))
df = pd.concat([df, counters.apply(pd.Series).fillna(0).astype(int)], axis=1)
c2 = df['Text'].apply(lambda t:Counter(re.findall(r'\b[a-z]+\b', t.lower())))
df['other_words'] = (c2 - counters).apply(lambda d:sum(d.values()))
其中的 Output 与第一个代码示例相同。 请注意,在 Python 3.10 及更高版本中,您应该可以使用新的total
function:
(c2 - counters).apply(Counter.total)
作为替代方案,你可以试试这个:
counts = (df['Text'].str.lower().str.findall(r'\b[a-z]+\b')
.apply(lambda x: pd.Series(x).value_counts())
.filter(map(str.lower, wordlist)).fillna(0))
df[counts.columns] = counts
print(df)
'''
№ Text i love
0 1 I love you forever... other words 1.0 1.0
1 2 No , i know that you know xxx words 1.0 0.0
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.