【问题标题】:String Matching and get more than 1 column in Pandas字符串匹配并在 Pandas 中获得超过 1 列
【发布时间】:2019-05-02 08:46:08
【问题描述】:

我需要将 df1 中的 Name 匹配到 df2 中的 Item_Name。只要名称匹配,我还需要来自 df2 的 Item_IdMaterial_Name

我有两个数据框:

Df1:

原始 df 有 1000+ 个名称

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

2nd Df:

原始 df 有 1000+ Item_Name

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_IDMaterial_Name 时,这可以正常工作。

问:

如果有其他方法不运行该函数两次需要帮助,但我可以一次获得 2 或 3 列

【问题讨论】:

  • 你想做什么?很难解释您的预期输出
  • 另外,df2[['Item_ID','Name']] 你的意思是df2[['Item_ID','Item_Name']]
  • 更新问题
  • 这对于您的预期输出仍然没有意义。例如为什么 Paper Bag 和 df2 的第 1、2、3 项匹配?
  • 当前代码双向匹配..这就是我想要的..如果复合词中的任何一个词匹配..那么它就是一个匹配!所以他们的匹配没有问题,我得到的唯一问题是如何获得两列

标签: python string pandas string-matching


【解决方案1】:

这是使用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

【讨论】:

    【解决方案2】:

    您可以尝试从查询中获取 Item_IDMaterial_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)
    

    【讨论】:

    • 对不起,我无法测试这段代码,但请告诉我它是怎么回事
    • 我们不能在这里使用map函数以某种方式将它放在一行中
    • 另外,我们只是传递了 Item_Id,我怎样才能在预期的输出中得到两个列名
    猜你喜欢
    • 2017-08-09
    • 2022-01-10
    • 2014-05-07
    • 2016-06-09
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    • 2019-08-30
    相关资源
    最近更新 更多