pandas算法慢:for循环和lambda

时间:2017-09-27 13:42:15

标签: python pandas levenshtein-distance

摘要:我正在寻找一堆数据之间的拼写错误,而且它正在永远消失

我正在迭代几个CSV文件(总计数百万行?),每一个我都在迭代一个json子值,它可能有200个字符串要搜索。对于每个循环或json值,我向每个数据帧添加一列,然后使用lambdas函数使用Levenshtein的搜索算法来查找拼写错误。然后我输出包含潜在拼写错误的任何行的结果 代码:

for file in file_list:  #20+ files             
df = pd.read_csv(file, usecols=["search column","a bunch of other columns...") #50k lines each-ish
for v in json_data.values():  #30 ish json values
    for row in v["json_search_string"]:    #200 ish substrings
        df_temp = df
        df_temp['jelly'] = row
        df_temp['difference'] = df_temp.apply(lambda x: jellyfish.levenshtein_distance(x['search column'],x['jelly']), axis=1)
        df_agg = df_temp[df_temp['difference'] <3]
        if os.path.isfile(filepath+"levenshtein.csv"):
            with open(filepath+"levenshtein.csv", 'a') as f:
                df_agg.to_csv(f, header=False)
        else:
            df_agg.to_csv(filtered_filepath+"levenshtein.csv") 

之前我尝试过相同的算法,但只是为了保持简短,而不是通过每个CSV的所有JSON值进行迭代,我只是做了一个这样的JSON值:

for file in file_list:  #20+ files             
    df = pd.read_csv(file, usecols=["search column","a bunch of other columns...") #50k lines each-ish
    for row in data['z']['json_search_string']:
        #levenshtein algorithm above

以上循环需要 100分钟才能完成! (编辑:每次运行lambda函数大约需要1-3秒)并且JSON文件中大约有30个。关于如何压缩算法并使其更快的任何想法?我想也许我可以把所有200个json子字符串并将它们作为列添加到每个df中,并以某种方式运行一个lambda函数,一次搜索所有列,但我不知道该怎么做。这样我每次只会迭代20个文件30次,而不是第三层for循环添加的数千次迭代。想法?

注意: 以下是数据可能的示例: JSON数据

{
"A": {
    "email": "blah",
    "name": "Joe Blah",
    "json_search_string": [
        "Company A",
        "Some random company name",
        "Company B",
        "etc",
        "..."

和csv列:

ID, Search Column,            Other Columns
1,  Clompany A,               XYZ
2,  Company A,                XYZ
3,  Some misspelled company,  XYZ
etc

2 个答案:

答案 0 :(得分:0)

嗯,很难回答性能提升问题。 根据努力和表现,这里有一些建议。

  1. 通过重新安排代码逻辑进行小幅调整。努力:小。预期增强:小。通过查看代码,我知道您要将File(数字20)中的单词与固定JSON File(仅一个)进行比较。为什么不首先从JSON File准备固定单词列表,并将其用于以下所有比较,而不是为每个File阅读JSON File?逻辑如下:

    # prepare fixed words from JSON DATA
    fixed_words = [] 
    for v in json_data.values():
        fixed_words += v["json_search_string"]
    # looping over each file, and compare them with word from fixed words
    for f in file_list:
        # do the comparison and save.
    
  2. 使用多处理。努力:小。预期增强:中位数。由于您的所有工作都相似,为什么不尝试多处理?您可以对每个文件应用多处理或在执行dataframe.apply时应用多处理。多处理有很多来源,请看一下。您的案例很容易实现。

  3. 使用其他语言实现Levenshtein距离。代码的瓶颈是Levenshtein距离的计算。你使用了水母python包,这是一个纯粹的python(当然,性能对于大型集合来说并不好)。以下是其他一些选择:

    一个。已经存在具有C / C ++实现的python包。努力:小。预期增强:高。感谢@Corley Brigman的评论,editdistance是您可以使用的一个选项。

    湾Cyphon自我实现。努力:中位数。增强:中位数或高位。检查pandas文档Performance

    ℃。由C / C ++自我实现作为包装器。努力:高;预期增强:高。查看Wrapping with C/C++

  4. 您可以使用我的一些建议来获得更高的性能。 希望这会有所帮助。

答案 1 :(得分:0)

您可以将代码更改为:

for file in file_list:  #20+ files             
    df = pd.read_csv(file, usecols=["search column","a bunch of other columns...") #50k lines each-ish
    x_search  = x['search column']
    for v in json_data.values():  #30 ish json values
        for row in v["json_search_string"]:    #200 ish substrings
            mask = [jellyfish.levenshtein_distance(s1,s2) < 3  for s1,s2 in zip(x_search, row) ] 
            df_agg = df_temp[mask]
            if os.path.isfile(filepath+"levenshtein.csv"):
                with open(filepath+"levenshtein.csv", 'a') as f:
                    df_agg.to_csv(f, header=False)
            else:
                df_agg.to_csv(filtered_filepath+"levenshtein.csv") 

apply会返回一份可能更贵的系列副本:

a = range(10**4)
b = range(10**4,2*(10**4))
%timeit [ (x*y) <3 for x,y in zip(a,b)]
%timeit pd.DataFrame([a,b]).apply(lambda x: x[0]*x[1] < 3 )

1000次循环,最佳3次:每次循环1.23 ms

1个循环,最佳3:668 ms每个循环