Как распараллелить многие (нечеткие) сравнения строк, применяя в Pandas?

У меня есть следующая проблема:

У меня есть dataframe master, который содержит предложения, такие как

master
Out[8]: 
                  original
0  this is a nice sentence
1      this is another one
2    stackoverflow is nice

Для каждой строки в Master, я ищу в другом фрейме slave для наилучшего соответствия с помощью fuzzywuzzy. Я использую fuzzywuzzy, потому что согласованные предложения между двумя файлами данных могут немного отличаться (дополнительные символы и т.д.).

Например, slave может быть

slave
Out[10]: 
   my_value                      name
0         2               hello world
1         1           congratulations
2         2  this is a nice sentence 
3         3       this is another one
4         1     stackoverflow is nice

Вот полнофункциональный, замечательный, компактный рабочий пример:)

from fuzzywuzzy import fuzz
import pandas as pd
import numpy as np
import difflib


master= pd.DataFrame({'original':['this is a nice sentence',
'this is another one',
'stackoverflow is nice']})


slave= pd.DataFrame({'name':['hello world',
'congratulations',
'this is a nice sentence ',
'this is another one',
'stackoverflow is nice'],'my_value': [2,1,2,3,1]})

def fuzzy_score(str1, str2):
    return fuzz.token_set_ratio(str1, str2)

def helper(orig_string, slave_df):
    #use fuzzywuzzy to see how close original and name are
    slave_df['score'] = slave_df.name.apply(lambda x: fuzzy_score(x,orig_string))
    #return my_value corresponding to the highest score
    return slave_df.ix[slave_df.score.idxmax(),'my_value']

master['my_value'] = master.original.apply(lambda x: helper(x,slave))

вопрос в 1 миллион долларов: могу ли я распараллелить свой применяемый код выше?

В конце концов, каждая строка в master сравнивается со всеми строками в slave (ведомый - это небольшой набор данных, и я могу хранить много копий данных в ОЗУ).

Я не понимаю, почему я не мог запускать несколько сравнений (т.е. обрабатывать несколько строк одновременно).

Проблема: я не знаю, как это сделать или если это возможно.

Любая помощь очень ценится!

Ответ 1

Вы можете распараллелить это с помощью Dask.dataframe. Это будет работать почти так же, за исключением того, что вы не можете использовать назначение столбцов и вместо этого использовать метод assign

>>> dmaster = dd.from_pandas(master, npartitions=4)
>>> dmaster = dmaster.assign(my_value=dmaster.original.apply(lambda x: helper(x, slave), name='my_value'))
>>> dmaster.compute()
                  original  my_value
0  this is a nice sentence         2
1      this is another one         3
2    stackoverflow is nice         1

Кроме того, вы должны подумать о компромиссах между использованием потоков и процессов здесь. Ваша нечеткая последовательность строк почти наверняка не освобождает GIL, так что вы не получите никакой пользы от использования нескольких потоков. Однако использование процессов приведет к сериализации и перемещению данных по вашей машине, что может немного замедлить работу.

Вы можете экспериментировать между использованием потоков и процессов или распределенной системой, управляя аргументом ключевого слова get= методу compute().

import dask.multiprocessing
import dask.threaded

>>> dmaster.compute(get=dask.threaded.get)  # this is default for dask.dataframe
>>> dmaster.compute(get=dask.multiprocessing.get)  # try processes instead