【问题标题】:pandas join with condition using LIKE operatorpandas 使用 LIKE 运算符加入条件
【发布时间】:2021-08-09 15:11:33
【问题描述】:

我有 2 个数据框: 用户

 user_id    position
0   201 Senior Engineer
1   207 Senior System Architect
2   223 Senior account manage
3   212 Junior Manager
4   112 junior Engineer
5   311 junior python developer
df1 = pd.DataFrame({'user_id': ['201', '207', '223', '212', '112', '311'],
                   'position': ['Senior Engineer', 'Senior System Architect', 'Senior account manage', 'Junior Manager', 'junior Engineer', 'junior python developer']})

角色

 role_id     role_position
0   10         %senior%
1   20         %junior%
df2 = pd.DataFrame({'role_id': ['10', '20'],
                   'role_position': ['%senior%', '%junior%']})

我想加入他们以获取 df1 中每一行的 role_id,使用条件如下:

lower(df1.position) LIKE df2.role_position

我想使用运算符 LIKE(就像在 SQL 中一样)。 所以它看起来像这样(或者没有 role_position - 它会更好):

user_id position                role_id  role_position
0   201 Senior Engineer           10      %senior%
1   207 Senior System Architect   10      %senior%
2   223 Senior account manage     10      %senior%
3   212 Junior Manager            20      %junior%
4   112 junior Engineer           20      %junior%
5   311 junior python developer   20      %junior%

我怎样才能做到这一点? 感谢您的帮助!

【问题讨论】:

  • 嗨!以下任何一个答案是否有效?如果是这样并且如果您愿意,您可以考虑接受其中一个以向其他人发出问题已解决的信号。如果没有,您可以提供反馈,以便改进(或完全删除)

标签: python pandas dataframe join sql-like


【解决方案1】:

你可以使用str.extract()+merge():

pat='('+'|'.join(df2['role_position'].str.strip('%').unique())+')'
df1['role_position']='%'+df1['position'].str.lower().str.extract(pat,expand=False)+'%'
df1=df1.merge(df2,on='role_position',how='left')

df1的输出:

user_id position                role_id  role_position
0   201 Senior Engineer           10      %senior%
1   207 Senior System Architect   10      %senior%
2   223 Senior account manage     10      %senior%
3   212 Junior Manager            20      %junior%
4   112 junior Engineer           20      %junior%
5   311 junior python developer   20      %junior%

【讨论】:

    【解决方案2】:

    如果资历级别总是从前面开始,您可以通过直接发送merge 来节省一些麻烦:

    print (pd.merge(df, df2,
                    left_on=df["position"].str.split().str[0].str.lower(),
                    right_on=df2["role_position"].str.strip("%")).drop("key_0", axis=1))
    

    否则,您可以在merge 期间执行pd.Series.str.extract

    pat = f'({"|".join(df2["role_position"].str.strip("%"))})'
    
    print (pd.merge(df, df2,
                    left_on=df["position"].str.extract(pat, flags=re.IGNORECASE, expand=False).str.lower(),
                    right_on=df2["role_position"].str.strip("%")).drop("key_0", axis=1))
    

    两者产生相同的结果:

      user_id                 position role_id role_position
    0     201          Senior Engineer      10      %senior%
    1     207  Senior System Architect      10      %senior%
    2     223    Senior account manage      10      %senior%
    3     212           Junior Manager      20      %junior%
    4     112          junior Engineer      20      %junior%
    5     311  junior python developer      20      %junior%
    

    【讨论】:

      【解决方案3】:

      可能性:


          df1['Similarity'] = 0
              df1['Role'] = 0
              
              from difflib import SequenceMatcher
              def similar(a, b):
                  return SequenceMatcher(None, a, b).ratio()
              
              for index, row in df1.iterrows(): 
                  for x in df2['role_position']:
                      z = similar(row['position'],x)
                      if z >= 0.20: 
                          df1.loc[index, "Similarity"] = z
                          df1.loc[index, "Role"] = x
      

      【讨论】:

        【解决方案4】:

        您可以生成映射字典,然后映射值:

        df2['role_position'] = df2['role_position'].str.strip('%')
        mappings = df2.set_index('role_position').to_dict('dict')['role_id']
        
        >> mappings
        {'senior': '10', 'junior': '20'}
        

        使用正则表达式我们可以提取每个位置的角色:

        re_roles = f"({df2['role_position'].str.cat(sep='|')})"
        
        position = df1['position'].str.extract(re_roles, flags=re.I).iloc[:, 0].str.lower()
        >> position 
        
        0    senior
        1    senior
        2    senior
        3    junior
        4    junior
        5    junior
        Name: 0, dtype: object
        

        最后使用映射字典映射role_id

        df1['role_id'] = position.map(mappings)
        
        >> df1 
        
          user_id                 position role_id
        0     201          Senior Engineer      10
        1     207  Senior System Architect      10
        2     223    Senior account manage      10
        3     212           Junior Manager      20
        4     112          junior Engineer      20
        5     311  junior python developer      20
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-26
          • 2021-07-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-11
          • 2015-07-01
          • 2018-12-13
          相关资源
          最近更新 更多