0

我有一个包含句子的数据框系列。(有些有点长)

我还有 2 个字典,其中包含单词作为键和整数作为计数。

并非所有字符串中的单词都出现在两个字典中。有些只在一个中,有些则没有。

数据帧长 124011 个单位。函数让我每串大约 0.4 个。这太长了。

W 只是字典的参考值 (weights = {}, weights[W] = {})

这是功能:

def match_share(string, W, weights, rel_weight):

    words = string.split()

    words_counts = Counter(words)

    ratios = []

    for word in words:

        if ((word in weights[W].keys())&(word in rel_weight[W].keys())):

            if (weights[W][word]!=0):

                ratios.append(words_counts[word]*rel_weight[W][word]/weights[W][word])

        else:

            ratios.append(0)

    if len(words)>0:

        ratios = np.divide(ratios, float(len(words)))

    ratio = np.sum(ratios)

    return ratio

谢谢

4

3 回答 3

1

我认为您的时间效率低下可能来自您使用 Counter 而不是 dict 的事实。这里的一些讨论 表明 dict 类的部分是用纯 c 编写的,而 counter 是用 python 编写的。

我建议将您的代码更改为使用 dict 并测试以查看是否可以提供更快的时间

另外为什么此代码重复?:

words = string.split()

words_counts = Counter(words)

words = string.split()

words_counts = Counter(words)

ratios = []
于 2017-04-02T23:57:37.437 回答
1

让我们清理一下:

def match_share(string, W, weights, rel_weight):

    words = string.split()

    words_counts = Counter(words)

    words = string.split()

    words_counts = Counter(words)

那是多余的!将 4 条语句替换为 2 条:

def match_share(string, W, weights, rel_weight):

    words = string.split()    
    words_counts = Counter(words)

下一个:

    ratios = []

    for word in words:    

        if ((word in weights[W].keys())&(word in rel_weight[W].keys())):

            if (weights[W][word]!=0):

                ratios.append(words_counts[word]*rel_weight[W][word]/weights[W][word])

        else:

            ratios.append(0)

我不知道您认为该代码会做什么。我希望你没有狡猾。但.keys返回一个可迭代的,并且X in <iterable>X in <dict>. 另外,请注意:weights[W][word] != 0如果最里面的 ( ) 条件失败,则不要附加任何内容。这可能是一个错误,因为您尝试在另一个 else 条件中附加 0。(我不知道你在做什么,所以我只是指出来。)这是 Python,而不是 Perl、C 或 Java。所以周围不需要括号if <test>:

让我们开始吧:

    ratios = []

    for word in words:
        if word in weights[W] and word in rel_weight[W]:
            if weights[W][word] != 0:    
                ratios.append(words_counts[word] * rel_weight[W][word] / weights[W][word])

        else:
            ratios.append(0)

下一个:

    if len(words)>0:

        ratios = np.divide(ratios, float(len(words)))

你试图防止被零除。但是您可以使用列表的真实性来检查这一点,并避免比较:

    if words:
        ratios = np.divide(ratios, float(len(words)))

其余的都很好,但你不需要变量。

    ratio = np.sum(ratios)

    return ratio

应用这些模块后,您的函数如下所示:

def match_share(string, W, weights, rel_weight):

    words = string.split()    
    words_counts = Counter(words)
    ratios = []

    for word in words:
        if word in weights[W] and word in rel_weight[W]:
            if weights[W][word] != 0:    
                ratios.append(words_counts[word] * rel_weight[W][word] / weights[W][word])

        else:
            ratios.append(0)

    if words:
        ratios = np.divide(ratios, float(len(words)))

    ratio = np.sum(ratios)
    return ratio

仔细看一下,我看到你正在这样做:

word_counts = Counter(words)

for word in words:
    append(   word_counts[word] * ...)

根据我的说法,这意味着如果“apple”出现 6 次,您将在列表中附加 6*...,每个单词一次。因此,您的列表中将出现 6 次不同的 6*...。你确定那是你想要的吗?还是应该for word in word_counts只迭代不同的单词?

另一个优化是从循环内部删除查找。即使 的值从不改变,您仍会继续查找weights[W]和。让我们在循环之外缓存这些值。另外,让我们缓存一个指向该方法的指针。rel_weight[W]Wratios.append

def match_share(string, W, weights, rel_weight):

    words = string.split()    
    words_counts = Counter(words)
    ratios = []

    # Cache these values for speed in loop
    ratios_append = ratios.append
    weights_W = weights[W]
    rel_W = rel_weight[W]

    for word in words:
        if word in weights_W and word in rel_W:
            if weights_W[word] != 0:    
                ratios_append(words_counts[word] * rel_W[word] / weights_W[word])

        else:
            ratios_append(0)

    if words:
        ratios = np.divide(ratios, float(len(words)))

    ratio = np.sum(ratios)
    return ratio

试试看,看看它是如何工作的。请查看上面的粗体注释和问题。可能存在错误,可能有更多方法可以加快速度。

于 2017-04-03T00:09:37.003 回答
1

如果您有该函数执行的概要文件会很好,但这里有一些通用的想法:

  1. 您在每次迭代中都不必要地获得一些元素。您可以在循环之前提取这些

例如

weights_W = weights[W]
rel_weights_W = rel_weights[W]
  1. 你不需要调用.keys()dicts。

这些是等价的:

word in weights_W.keys()
word in weights_W
  1. 尝试在不先查找值的情况下获取值。这将为您节省一次查找。

例如,而不是:

if ((word in weights[W].keys())&(word in rel_weight[W].keys())):
        if (weights[W][word]!=0):

你可以做:

word_weight = weights_W.get(word)
if word_weight is not None:
    word_rel_weight = rel_weights_W.get(word)
    if word_rel_weight is not None:
        if word_weight != 0:  # lookup saved here
于 2017-04-03T00:12:16.607 回答