Как распараллелить многие (нечеткие) сравнения строк, применяя в 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