Строка соответствия и получить более 1 столбца в Pandas - PullRequest
0 голосов
/ 30 ноября 2018

Мне нужно сопоставить Name от df1 до Item_Name от df2.Везде, где совпадает имя, мне также нужны Item_Id и Material_Name от df2.

У меня есть два фрейма данных:

Df1:

Исходный df имеет 1000+ Name

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

2-й DF:

Исходный df имеет 1000+ Имя_имя

Item_ID   Item_Name    Material_Name
1         Paper Bag      Office
2         wallpaper      Decor
3         paper          Office
4         cat cage       Animal Misc
5         good cat       Animal

Ожидаемый результат:

Id Name              Item_ID      Material_Name
1  Paper              1,2,3       Office,Decor,Office 
2  Paper Bag          1,2,3       Office,Decor,Office 
3  Scissors            NA         NA 
4  Mat                 NA         NA  
5  Cat                4,5         Animal Misc, Animal
6  Good Cat           4,5         Animal Misc,Animal

Код:

def matcher(query):

    matches = [i['Item_ID'] for i in df2[['Item_ID','Name']].to_dict('records') if any(q in i['Name'].lower() for q in query.lower().split())]
    if matches:
        return ','.join(map(str, matches))
    else:
        return 'NA'

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

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

ASK:

Нужна помощь, если есть другой способ не запускать функцию дважды , но я могу получить даже 2 или 3 столбца водин раз

Ответы [ 2 ]

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

Вот один из способов использования pd.DataFrame.loc и повторного использования логических масок:

def matcher(x):

    # construct 2-way mask
    m1 = df2['Item_Name'].str.contains(x, regex=False, case=False)
    m2 = [any(w in i.lower() for w in x.lower().split()) for i in df2['Item_Name']]

    # apply 2-way mask
    res_id = df2.loc[m1 | m2, 'Item_ID']
    res_mat = df2.loc[m1 | m2, 'Material_Name']

    return ','.join(res_id.astype(str)), ','.join(res_mat.astype(str))

df1[['Item_ID', 'Material_Name']] = pd.DataFrame(df1['Name'].apply(matcher).tolist())

print(df1)

   Id       Name Item_ID        Material_Name
0   1      Paper   1,2,3  Office,Decor,Office
1   2  Paper Bag   1,2,3  Office,Decor,Office
2   3   Scissors                             
3   4        Mat                             
4   5        Cat     4,5   Animal Misc,Animal
5   6   Good Cat     4,5   Animal Misc,Animal
0 голосов
/ 30 ноября 2018

Вы можете попробовать получить как Item_ID, так и Material_Name как кортеж из вашего запроса, а затем применить соответствующий столбец с [i[0] for i in matches] или [i[1] for i in matches].

def matcher(query):
    matches = [(i['Item_ID'], i['Material_Name']) for i in df2[['Item_ID','Name']].to_dict('records') if any(q in i['Name'].lower() for q in df1['Name'].lower().split())]

    if matches:
        df1['Material_Name'].apply(','.join(map(str, [i[1] for i in matches])))
        return ','.join(map(str, [i[0] for i in matches]))
    else:
        df1['Material_Name'].apply("NA")
        return 'NA'

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