繁体   English   中英

Python 在 for 循环中查找字符串中的文本太慢

[英]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

笔记:

  • 我已将所有单词都转换为小写,这样您就不会分别计算Ii了。
  • 我使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM