加速这个循环 - python

时间:2017-07-14 00:16:11

标签: python python-2.7 performance pandas

从我的分析中,我可以看到此函数需要更多时间来处理。如何加快此代码的速度?我的数据集有超过一百万条记录,这里我给出的这个停用词列表只是一个样本 - 它实际上包含150个单词。

def remove_if_name_v1(s):
    stopwords = ('western spring','western sprin','western spri','western spr','western sp','western s',
                 'grey lynn','grey lyn','grey ly','grey l')
    for word in stopwords:
        s = re.sub(r'(' + word + r'.*?|.*?)\b' + word + r'\b', r'\1', s.lower(), 1)
    return s.title()

test.new_name = test.old_name.apply(lambda x: remove_if_name_v2(x) if pd.notnull(x) else x)

似乎函数是为数据框中的每一行运行的,并且在每一行中,它运行for循环的次数与停用词一样多。有没有替代方法?

我在这里要做的就是例子,如果字符串包含“西部春路西部春天”,这个功能将返回“西部春天路”。

感谢。

2 个答案:

答案 0 :(得分:3)

您可以组合并预编译正则表达式,以获得相当大的改进。

stopwords = ('western spring',
             'western sprin',
             'western spri',
             'western spr',
             'western sp',
             'western s',
             'grey lynn',
             'grey lyn',
             'grey ly',
             'grey l')

pat = re.compile(r'(?P<repl>(?P<word>{stopwords}).*?|.*?)\b(?P=word)\b'.format(
                 stopwords='|'.join(re.escape(s) for s in stopwords)))

test.old_name.str.replace(pat, '\g<repl>')

请注意(?P=word)反向引用。我还使用了Series.str.replace代替Series.apply,后者稍微清晰了。

答案 1 :(得分:2)

一个快速的改进是将停用词放在一组中。检查时,多个单词将导致一个恒定的时间O(1)查找。

STOP_WORDS = {
    'western spring',
    'western sprin',
    'western spri',
    'western spr',
    'western sp',
    'western s',
    'grey lynn',
    'grey lyn',
    'grey ly',
    'grey l'
}

def find_first_stop(words):
    if len(words) == 0:
        return False
    joined = ' '.join(reversed(words))
    if joined in STOP_WORDS:
        return True
    return find_first_stop(words[:-len(words) - 1])

def remove_if_name_v1(s):
    if s in STOP_WORDS:
        return s

    words = []
    split_words = s.split(' ')
    for word in reversed(split_words):
        words.append(word)
        if find_first_stop(words):
            words = []
    return ' '.join(reversed(words))

old_name = pd.Series(['western spring road western spring', 'kings road western spring', 'western spring'])
new_name = old_name.apply(lambda x: remove_if_name_v1(x) if pd.notnull(x) else x)
print(new_name)

输出:

0    western spring road
1             kings road
2         western spring
dtype: object