【问题标题】:Is there a way to use functions and not nested loops to improve the run time of the following process?有没有办法使用函数而不是嵌套循环来改善以下进程的运行时间?
【发布时间】:2020-10-01 14:57:48
【问题描述】:

我的问题是我有一个包含 cmets 的向量和另一个包含我试图在 cmets 中找到的名称的向量。我的方法是使用fuzzywuzzy,并在第一步中为每个名称分配它为相应评论获得的分数。这样我就可以在进一步的步骤中说出哪些评论中可能提到了哪些名字

例如,数据可能如下所示:

# in the original data both would be DFs with more than 1 column
names = pd.DataFrame(["Anna Starkow", "Marian Mueller", "James Leo Arneau"))

# spelling mistakes and abbreviations
Comments=pd.DataFrame(["Ana Starkov was super good!", "M. mueller is in great shape", "I like Arneau and Starkow's work","Thanks Anna Starkov, credits to JL Arneau"])

# my approach:

# This is also from stack
N = len(Comments.index)
M = len(names.index)

res= pd.DataFrame([[0] * M]*N)

#My code
DF=pd.concat([Comments.reset_index(drop=True), res],axis=1)


for x in range(len(Comments.index)):
    for i in range(len(names.index)):
        DF[x, i+1]=fuzz.token_set_ratio(DF.Comments[x],names.names[i])

但是,它一直运行并且没有返回结果。

我希望这样的事情会回来:

# Comments                         Anna Starkow  Marian Mueller ....
# Ana Starkov was super good!               80               0  ....
# M. mueller is in great shape               0              70  ....
# ....                                    ....            ....  ....

有没有更有效的方法来做到这一点?

我希望我的代码没有错误,因为我必须从不允许我使用 Stack 的另一台机器上键入它。

【问题讨论】:

    标签: python for-loop fuzzywuzzy fuzzy-comparison


    【解决方案1】:

    其他答案集中在加快分配结果的方法上。虽然这可能对性能略有帮助,但您真正的问题是与模糊伍兹匹配的字符串真的很慢。您可以优化两个部分:

    1. 当将两个字符串传递给 fuzz.token_sort_ratio 时,它将通过小写这些字符串、删除非字母数字字符和修剪空格来预处理这些字符串。由于您多次重复名称,因此您重复这项工作

    2. 即使使用 python-Levenshtein FuzzyWuzzy 在很多地方都没有真正优化。您应该将其替换为 RapidFuzz,它实现了具有相似接口的相同算法,但主要用 C++ 实现,并附带一些额外的算法改进,使其速度更快。

    from rapidfuzz import process, utils
    
    
    processed_names = [utils.default_process(name) for name in names.names]
    
    for x in range(len(Comments.index)):
        for i, name in enumerate(processed_names):
            DF[x, i+1]=fuzz.token_sort_ratio(
              utils.default_process(DF.Comments[x]), name, processor=None)
    
    

    如果您的错误匹配结果为 0,您可以通过传递 score_cutoff 来进一步提高性能:

    fuzz.token_sort_ratio(
      utils.default_process(DF.Comments[x]), name,
      processor=None, score_cutoff=<insert your minimum score here>)
    

    【讨论】:

    • 感谢您的帮助。我一定会试试这个包。你知道是否有可能使用 apply 之类的东西来进一步加快这个过程?因为它不会按名称检查名称,而是同时检查所有名称。
    • 我不怎么使用 pandas,但据我所知,pandas apply 也没有使用多核。您可以为此使用多处理 (stackoverflow.com/questions/61242598/…)。
    【解决方案2】:

    这里的问题与其说是 Python,不如说是 DataFrame,无论您是在处理 Pandas 还是 PySpark,它的工作方式都与 SQL 表类似:只要有可能,您应该对 DF 上的操作进行矢量化处理。这让计算机不必担心算法的并行化。

    如果您有一个预先存在的 DF,您可以使用 pandas.DataFrame.apply() 有效地将函数应用于每个元素。

    在您的情况下,您似乎只是在寻找一种更好的方法来初始化 DF。如果您可以将您的 DF 内容描述为字典列表(每条记录一个字典),我建议使用 pandas.DataFrame.from_records()。列表中的每个 dict 都会有一个类似 {'Comments': 'Ana Starkov was super good!', 'Anna Starkow': 80, 'Marian Mueller': 0} 的形式(from_dict() 方法在概念上相似,但输入格式略有不同。)

    这将比逐个单元地构建/重写 DF 快得多。

    【讨论】:

      【解决方案3】:

      您可以尝试以下方法:

       i=0
       l0=[]
       for comment in Comments[0]:
         l=[]
         for name in names[0]:
       
           l.append(fuzz.token_sort_ratio(comment,name))
       
         l0.append(l)
       
       DF_out=pd.concat([Comments.reset_index(drop=True), pd.DataFrame(np.matrix(l0)) ],axis=1)
      

      【讨论】:

        猜你喜欢
        • 2010-09-30
        • 2021-10-22
        • 2019-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-11
        相关资源
        最近更新 更多