代码之家  ›  专栏  ›  技术社区  ›  Rahul Agarwal

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

  •  2
  • Rahul Agarwal  · 技术社区  · 7 年前

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

    df1:原始df有2000行名称

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

    第二个df:原始df有1000+项\名称

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

    我需要列中的字符串 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])
    

    问题是,它会很慢,我想要的输出是从模糊中得到的。输出如下:

    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,则如何执行str.contains
    2. 如何转换df以获得上述预期输出
    3 回复  |  直到 7 年前
        1
  •  3
  •   jpp    7 年前

    你可以用 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 是一个逐行循环。
    • 使用列表理解而不是 P.S.系列申请 . 两者都是python级别的循环,但是列表理解通常优于panda str 方法。

    但上述方法并不能提高算法的复杂性。为了更好地提高数量级,您应该考虑基于trie的算法,例如 this answer 利用 Aho–Corasick algorithm .

        2
  •  1
  •   Shrey    7 年前

    你可以使用 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
    

    相信这会给你期望的结果

        3
  •  0
  •   min2bro    7 年前
    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]