字符串在python中包含两个df之间

时间:2018-11-27 10:12:24

标签: python string pandas performance string-matching

我有两个带有两个字符串列的df,如下所示:

Df1:原始df具有2000行名称

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

第二个Df:原始df有1000多个Item_Name

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

我需要列{strong> Item_Name

中的列Name中的字符串

第一种方法:使用str.contains

我知道如何匹配字符串(如果它们是一列和几个要匹配的字符串),如下所示:

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

但是当有两列字符串(名称和项目名称)要匹配时怎么办

第二种方法: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])

问题将是,它会很慢,而我想要的输出比我从Fuzzywuzzy得到的还要多。输出如下:

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 :(得分:3)

您可以将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方法。

但是以上内容并没有提高算法的复杂性。为了获得更好的数量级改进,应考虑使用基于Trie的算法,例如使用this answerAho–Corasick algorithm

答案 1 :(得分:1)

您可以在此处使用 var a; // undefined if (a) { console.log('1'); } else { console.log('2'); } if (!!a) { console.log('1'); } else { console.log('2'); }

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)

相信这会给您想要的结果

答案 2 :(得分:0)

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]