¿Cómo paralelizar muchas comparaciones de cadenas (difusas) usando aplicar en Pandas?

tengo el siguiente problema

Tengo un maestro de marcos de datos que contiene oraciones, como

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

Por cada fila en Master, busco en otro esclavo Dataframe para la mejor coincidencia usando fuzzywuzzy . Uso fuzzywuzzy porque las oraciones coincidentes entre los dos marcos de datos podrían diferir un poco (caracteres adicionales, etc.).

Por ejemplo, esclavo podría ser

 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 

Aquí hay un ejemplo de funcionamiento compacto, maravilloso y completamente funcional 🙂

 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)) 

La pregunta de 1 millón de dólares es: ¿puedo paralelizar mi código de solicitud anterior?

Después de todo, cada fila en el master se compara con todas las filas en el slave (el esclavo es un pequeño conjunto de datos y puedo guardar muchas copias de los datos en la RAM).

No veo por qué no puedo ejecutar varias comparaciones (es decir, procesar varias filas al mismo tiempo).

Problema: no sé cómo hacerlo o si eso es posible.

Cualquier ayuda muy apreciada!

Puede paralelizar esto con Dask.dataframe.

 >>> dmaster = dd.from_pandas(master, npartitions=4) >>> dmaster['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 

Además, deberías pensar en las ventajas y desventajas entre el uso de procesos de subprocesos vs aquí. Su coincidencia de cadenas difusas casi con seguridad no libera la GIL, por lo que no obtendrá ningún beneficio del uso de múltiples hebras. Sin embargo, el uso de procesos hará que los datos se serialicen y se muevan alrededor de su máquina, lo que podría ralentizar un poco las cosas.

Puede experimentar entre el uso de subprocesos y procesos o un sistema distribuido administrando el argumento get= keyword al método 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 

Estoy trabajando en algo similar y quería proporcionar una solución de trabajo más completa para cualquier otra persona con la que pudiera encontrar esta pregunta. Desgraciadamente, @MRocklin tiene algunos errores de syntax en los fragmentos de código proporcionados. No soy experto en Dask, por lo que no puedo comentar sobre algunas consideraciones de rendimiento, pero esto debería cumplir su tarea tal como lo sugirió @MRocklin. Esto está usando la versión 0.17.2 de Dask y la versión 0.22.0 de Pandas :

 import dask.dataframe as dd import dask.multiprocessing import dask.threaded from fuzzywuzzy import fuzz import pandas as pd 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': [1,2,3,4,5]}) def fuzzy_score(str1, str2): return fuzz.token_set_ratio(str1, str2) def helper(orig_string, slave_df): 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.loc[slave_df.score.idxmax(),'my_value'] dmaster = dd.from_pandas(master, npartitions=4) dmaster['my_value'] = dmaster.original.apply(lambda x: helper(x, slave),meta=('x','f8')) 

Luego, obtenga sus resultados (como en esta sesión de intérprete):

 In [6]: dmaster.compute(get=dask.multiprocessing.get) Out[6]: original my_value 0 this is a nice sentence 3 1 this is another one 4 2 stackoverflow is nice 5