Строка содержит между двумя df в python - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть два df с двумя строковыми столбцами, как показано ниже:

Df1: у исходного df есть 2000 строк имен

Id    Name
1     Paper
2     Paper
3     Scissors
4     Mat
5     Cat
6     Cat

2nd Df: у исходного df есть 1000+ Item_Name

Item_ID   Item_Name
1         Paper Bag
2         wallpaper
3         paper
4         cat cage

Мне нужны строки в столбце Name, которые находятся в столбце Item_Name

1-й подход: с помощью str.contains:

Я знаю, каксопоставить строку, если их был один столбец и несколько строк для сопоставления, как показано ниже:

df[df['Name'].str.contains("paper|cat", na=False)]

Но как это сделать, если есть два столбца строки (name & Item_name), которые должны быть сопоставлены ?

2-й подход: Fuzzywuzzy

matched = []
for row in df1.index:
    name = df1.get_value(row,"Name")
    for columns in df2.index:
        item_name=df2.get_value(columns,"Item_Name")
        matched_token=fuzz.token_sort_ratio(name,item_name)
        if matched_token> 80:
            matched.append([name,item_name,matched_token])

Проблема будет в том, что он будет медленным, и мой желаемый результат - это немного больше, чем я получаю от нечетких слов.Вывод выглядит следующим образом:

Id Name     Item_ID
1  Paper     1,2,3
2  Paper     1,2,3
3  Scissors  NA 
4  Mat       NA 
5  Cat       4
6  Cat       4 

Суммировать :

  1. Как сделать str.contains, если их два df с другим именем столбца
  2. Как преобразовать df для получения указанного выше результата

Ответы [ 3 ]

0 голосов
/ 27 ноября 2018
df=pd.DataFrame({'ID':[1,2,3,4,5,6],'Name':['paper','paper','scissors','mat','cat','cat']})
df1=pd.DataFrame({'ID':[1,2,3,4],'Name':['paper bag','wallpaper','paper','cat cage']})


import numpy as np
def lookup_prod(ip):
    lst=[]
    for idx,row in df1.iterrows():
        if ip in row['Name']:
            lst.append(row['ID'])    
    if not lst:
        return np.NaN
    return lst

df['Item_ID'] = df['Name'].apply(lookup_prod)

Выход:

 ID  Name         Item_ID
0   1   paper     [1, 2, 3]
1   2   paper     [1, 2, 3]
2   3   scissors    NaN
3   4   mat         NaN
4   5   cat         [4]
5   6   cat         [4]
0 голосов
/ 27 ноября 2018

Вы можете использовать df.apply здесь

def get_vals(df):
    return ','.join(map(str, df2.loc[df2['Item_Name'].str.contains(df['Name'], case=False),]['Item_ID'].tolist()))

df1['Item_ID'] = df1.apply(get_vals, axis=1)

Выход:

Id     Name  Item_ID
1     Paper   1,2,3
2     Paper   1,2,3
3  Scissors        
4       Mat        
5       Cat       4
6       Cat       4

Поверьте, это даст вам желаемый результат

0 голосов
/ 27 ноября 2018

Вы можете использовать pd.Series.apply с пользовательской функцией:

def matcher(x):
    res = df2.loc[df2['Item_Name'].str.contains(x, regex=False, case=False), 'Item_ID']
    return ','.join(res.astype(str))

df1['Item_ID'] = df1['Name'].apply(matcher)

print(df1)

   Id      Name Item_ID
0   1     Paper   1,2,3
1   2     Paper   1,2,3
2   3  Scissors        
3   4       Mat        
4   5       Cat       4
5   6       Cat       4

Существуют способы сделать это более эффективным:

  • Только работадля уникальных элементов в df1['Name']: apply - строковый цикл.
  • Используйте списочные выражения вместо pd.Series.apply.Оба являются циклами уровня Python, но понимание списков часто превосходит методы Pandas str.

Но приведенное выше не улучшает алгоритмическую сложность.Для улучшения на порядок лучше, вы должны рассмотреть алгоритм на основе три, такой как этот ответ с использованием алгоритма Aho-Corasick .

...