首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >字优化器

字优化器
EN

Stack Overflow用户
提问于 2019-03-20 00:55:02
回答 1查看 77关注 0票数 1
代码语言:javascript
复制
for s_index, s in enumerate(sentences):
        s_tokens = s.split()
        if (local_q_set.intersection(set(s_tokens)) == local_q_set):
            q_results.append(s_index)

上面的代码片段是我在大量文本数据中查找相关句子的核心算法,其中包括查询中的所有标记。例如,对于查询“高兴的苹果”,它会查找所有给定标记中的一个或多个(即“高兴”和“苹果”)中的所有语句。我的方法非常简单:查找常见的相交集,并查看它们是否匹配。然而,我并没有得到足够的表现。如果有人看到了这样的问题的优化,我会非常感谢任何方向或链接的想法-谢谢您的时间提前。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-03-20 02:04:42

您可以做一些事情来提高顺序搜索的性能,但是真正的提升将来自索引标记。

set.difference

使用not local_q_set.difference(s_tokens)而不是将交集与原始集进行比较可能会更快一些。

正则表达式过滤器

如果您的句子很长,使用正则表达式可以通过将潜在的标记从句子中分离出来,从而提高一些速度,然后再根据令牌集检查这些标记:

代码语言:javascript
复制
import re
tokens     = re.compile("|".join(local_q_set))
tokenCount = len(local_q_set)
for s_index, s in enumerate(sentences):
    s_tokens = tokens.findall(s)
    if len(s_tokens) < tokenCount or local_q_set.difference(s.split()):
       continue
    q_results.append(s_index) 

使用in运算符的筛选器

您还可以使用一个简单的in操作符来检查令牌的存在,而不是一个正则表达式(当查询中没有几个令牌时,这会更快):

代码语言:javascript
复制
result = []
tokenSet = set(queryTokens)
for index, sentence in enumerate(sentences):
     if any( token not in sentence for token in queryTokens) \
     or tokenSet.difference(sentence.split()):
         continue
     result.append(index)

缓存语句词集

为了改进对同一个句子列表进行多个查询时的顺序搜索,您可以构建与这些句子对应的单词集的缓存。这将消除在分析句子以找到匹配的过程中的工作。

代码语言:javascript
复制
cachedWords = []

queryTokens = ["happy","apple"]

queryTokenSet = set(queryTokens)
if not cachedWords:
    cachedWords = [ set(sentence.split()) for sentence in sentences ]
result = [ index for index,words in enumerate(cachedWords) if not queryTokenSet.difference(words) ]

令牌索引

如果您要对相同的句子列表执行许多查询,那么在标记和句子索引之间创建一个映射会更有效。您可以使用字典来实现这一点,然后通过交叉查询标记的语句索引直接获得查询结果:

代码语言:javascript
复制
tokenIndexes = dict()
for index,sentence in enumerate(sentences):
    for token in sentence.lower().split():
        tokenIndexes.setdefault(token,[]).append(index)

def tokenSet(token): return set(tokenIndexes.get(token,[]))

queryTokens = ["happy","apple"]

from functools import reduce
result = reduce(set.intersection , (tokenSet(token) for token in queryTokens) )

这将允许您使用set运算符经济地实现复杂查询。例如:

代码语言:javascript
复制
import re

querySring = " happy & ( apple | orange | banana ) "
result = eval(re.sub("(\w+)",r"tokenSet('\1')", querySring)) 

# re.sub(...) transforms the query string into " tokenSet('happy') & ( tokenSet('apple') | tokenSet('orange') | tokenSet('banana') ) "

性能测试:

我做了一些性能测试(在80000个句子中找到两个标记):

代码语言:javascript
复制
original algorithm: 105 ms           1x
set.difference:      88 ms         1.2x
regular expression:  60 ms         1.8x
"in" operator:       43 ms         2.4x
caching word sets:   23 ms         4.6x (excluding 187ms to build cache)
token indexing:       0.0075 ms  14000x (excluding 238ms to build tokenIndexes)

因此,如果要对相同的句子执行多个查询,使用标记索引,那么一旦构建了tokenIndexes字典,响应速度将快14,000倍。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55252069

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档