Buscar múltiples claves de diccionario en un Pandas Dataframe y devolver múltiples valores para coincidencias

Publicación por primera vez, así que pido disculpas por adelantado si mi formateo está desactivado.

Aquí está mi problema:

He creado un dataframe de Pandas que contiene varias filas de texto:

d = {'keywords' :['cheap shoes', 'luxury shoes', 'cheap hiking shoes']} keywords = pd.DataFrame(d,columns=['keywords']) In [7]: keywords Out[7]: keywords 0 cheap shoes 1 luxury shoes 2 cheap hiking shoes 

Ahora tengo un diccionario que contiene las siguientes claves / valores:

 labels = {'cheap' : 'budget', 'luxury' : 'expensive', 'hiking' : 'sport'} 

Lo que me gustaría hacer es averiguar si existe una clave en el diccionario en el dataframe, y si es así, devolver el valor apropiado

Pude llegar a algo usando lo siguiente:

 for k,v in labels.items(): keywords['Labels'] = np.where(keywords['keywords'].str.contains(k),v,'No Match') 

Sin embargo, en la salida faltan las dos primeras teclas y solo se captura la última tecla “senderismo”

  keywords Labels 0 cheap shoes No Match 1 luxury shoes No Match 2 cheap hiking shoes sport 

Además, también me gustaría saber si hay una manera de capturar varios valores en el diccionario separados por | , entonces la salida ideal se vería así

  keywords Labels 0 cheap shoes budget 1 luxury shoes expensive 2 cheap hiking shoes budget | sport 

Cualquier ayuda u orientación es muy apreciada.

Aclamaciones

Ciertamente es posible. Aquí hay una forma.

 d = {'keywords': ['cheap shoes', 'luxury shoes', 'cheap hiking shoes', 'nothing']} keywords = pd.DataFrame(d,columns=['keywords']) labels = {'cheap': 'budget', 'luxury': 'expensive', 'hiking': 'sport'} df = pd.DataFrame(d) def matcher(k): x = (i for i in labels if i in k) return ' | '.join(map(labels.get, x)) df['values'] = df['keywords'].map(matcher) # keywords values # 0 cheap shoes budget # 1 luxury shoes expensive # 2 cheap hiking shoes budget | sport # 3 nothing 

Puede usar "|".join(labels.keys()) para obtener un patrón para ser usado por re.findall() .

 import pandas as pd import re d = {'keywords' :['cheap shoes', 'luxury shoes', 'cheap hiking shoes']} keywords = pd.DataFrame(d,columns=['keywords']) labels = {'cheap' : 'budget', 'luxury' : 'expensive', 'hiking' : 'sport'} pattern = "|".join(labels.keys()) def f(s): return "|".join(labels[word] for word in re.findall(pattern, s)) keywords.keywords.map(f) 

Siguiendo con su enfoque, podría hacer por ejemplo

 arr = np.array([np.where(keywords['keywords'].str.contains(k), v, 'No Match') for k, v in labels.items()]).T keywords["Labels"] = ["|".join(set(item[ind if ind.sum() == ind.shape[0] else ~ind])) for item, ind in zip(arr, (arr == "No Match"))] Out[97]: keywords Labels 0 cheap shoes budget 1 luxury shoes expensive 2 cheap hiking shoes sport|budget 

Me gusta la idea de usar replace primero y luego encontrar los valores.

 keywords.assign( values= keywords.keywords.replace(labels, regex=True) .str.findall(f'({"|".join(labels.values())})') .str.join(' | ') ) keywords values 0 cheap shoes budget 1 luxury shoes expensive 2 cheap hiking shoes budget | sport 

Podría split las cadenas en columnas separadas y luego stack en un índice múltiple, de modo que pueda map las tags a los valores. Luego, groupby el índice inicial y concatenate las cadenas que pertenecen a cada índice.

 keywords['Labels'] = keywords.keywords.str.split(expand=True).stack()\ .map(labels).groupby(level=0)\ .apply(lambda x: x.str.cat(sep=' | ')) keywords Labels 0 cheap shoes budget 1 luxury shoes expensive 2 cheap hiking shoes budget | sport