python - 百万行上的模糊正则表达式匹配 Pandas df

标签 python regex pandas multiprocessing fuzzy

我正在尝试检查字符串列和引用列表之间的模糊匹配。字符串系列包含超过 1 m 行,引用列表包含超过 10 k 条目。

例如:

df['NAMES'] = pd.Series(['ALEXANDERS', 'NOVA XANDER', 'SALA MANDER', 'PARIS HILTON', 'THE HARIS DOWNTOWN', 'APARISIAN', 'PARIS', 'MARIN XO']) # 1mil rows

ref_df['REF_NAMES'] = pd.Series(['XANDER','PARIS']) #10 k rows

###Output should look like 

df['MATCH'] = pd.Series([Nan, 'XANDER', 'MANDER', 'PARIS', 'HARIS', Nan, 'PARIS', Nan])

如果该单词单独出现在字符串中,它应该生成匹配项(并且在该字符串中,最多允许 1 个字符替换)

例如 - 'PARIS' 可以与 'PARIS HILTON'、'THE HARIS DOWNTOWN' 匹配,但不能与 'APARISIAN' 匹配。

类似地,'XANDER' 与 'NOVA XANDER' 和 'SALA MANDER' 匹配(MANDER 与 XANDER 有 1 个字符差异),但不会生成与 ' 的匹配亚历山大的。

到目前为止,我们已经编写了相同的逻辑(如下所示),尽管比赛需要 4 个小时以上才能运行。需要将其控制在 30 分钟以内。

当前代码 -

tags_regex = ref_df['REF_NAMES'].tolist()
tags_ptn_regex = '|'.join([f'\s+{tag}\s+|^{tag}\s+|\s+{tag}$' for tag in tags_regex])


def search_it(partyname):
    m = regex.search("("+tags_ptn_regex+ ")"+"{s<=1:[A-Z]}",partyname):
    if m is not None:
        return m.group()
    else:
        return None
    
df['MATCH'] = df['NAMES'].str.apply(search_it)

另外,多重处理对正则表达式有帮助吗?非常感谢!

最佳答案

正如您重复的那样,您的模式效率相当低tag在正则表达式中模式三次。您只需要创建一个具有所谓的空白边界的模式, (?<!\S)(?!\S) ,您只需要一个tag模式。

接下来,如果你有几千个选择,甚至是单个 tag模式正则表达式会非常慢,因为可能会出现在字符串中相同位置匹配的替代项,因此会出现太多回溯。

为了减少这种回溯,您将需要 regex trie .

这是一个工作片段:

import regex
import pandas as pd

## Class to build a regex trie, see https://stackoverflow.com/a/42789508/3832970
class Trie():
    """Regex::Trie in Python. Creates a Trie out of a list of words. The trie can be exported to a Regex pattern.
    The corresponding Regex should match much faster than a simple Regex union."""

    def __init__(self):
        self.data = {}

    def add(self, word):
        ref = self.data
        for char in word:
            ref[char] = char in ref and ref[char] or {}
            ref = ref[char]
        ref[''] = 1

    def dump(self):
        return self.data

    def quote(self, char):
        return regex.escape(char)

    def _pattern(self, pData):
        data = pData
        if "" in data and len(data.keys()) == 1:
            return None

        alt = []
        cc = []
        q = 0
        for char in sorted(data.keys()):
            if isinstance(data[char], dict):
                try:
                    recurse = self._pattern(data[char])
                    alt.append(self.quote(char) + recurse)
                except:
                    cc.append(self.quote(char))
            else:
                q = 1
        cconly = not len(alt) > 0

        if len(cc) > 0:
            if len(cc) == 1:
                alt.append(cc[0])
            else:
                alt.append('[' + ''.join(cc) + ']')

        if len(alt) == 1:
            result = alt[0]
        else:
            result = "(?:" + "|".join(alt) + ")"

        if q:
            if cconly:
                result += "?"
            else:
                result = "(?:%s)?" % result
        return result

    def pattern(self):
        return self._pattern(self.dump())

## Start of main code
df = pd.DataFrame()
df['NAMES'] = pd.Series(['ALEXANDERS', 'NOVA XANDER', 'SALA MANDER', 'PARIS HILTON', 'THE HARIS DOWNTOWN', 'APARISIAN', 'PARIS', 'MARIN XO']) # 1mil rows
ref_df = pd.DataFrame()
ref_df['REF_NAMES'] = pd.Series(['XANDER','PARIS']) #10 k row

trie = Trie()
for word in ref_df['REF_NAMES'].tolist():
    trie.add(word)

tags_ptn_regex = regex.compile(r"(?:(?<!\S)(?:{})(?!\S)){{s<=1:[A-Z]}}".format(trie.pattern()), regex.IGNORECASE)

def search_it(partyname):
    m = tags_ptn_regex.search(partyname)
    if m is not None:
        return m.group()
    else:
        return None
    
df['MATCH'] = df['NAMES'].apply(search_it)

关于python - 百万行上的模糊正则表达式匹配 Pandas df,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65286846/

相关文章:

python - conda 不被识别为内部或外部命令、可运行程序或批处理文件

python - 如何用从另一个文件(数组?)分配的变量替换一个文件中的字符串

python - 如何选择数据框中的特定数据并删除所有其他数据?

python - 具有多级列的数据透视表

python - PyMC3 在 Possion 模型创建期间生成错误

python - 如果不满足条件,则返回该用户的数据,否则另一个查询

javascript - JavaScript 中的 match 与 exec

python - 如何在找到第一个所需字符并复制其余文本后停止搜索?

python - 在for循环中创建pandas dfs

python - Bokeh 直方图不会绘制