代码之家  ›  专栏  ›  技术社区  ›  Ben

Pandas:使用字典基于不同列的条件部分替换

  •  1
  • Ben  · 技术社区  · 3 年前

    我对Python中字典的整体使用并不熟悉,但我相信它们对我的问题非常有用。 假设我有以下数据帧:

    df = pd.DataFrame({'NATIONALITY': {0: 'Germany', 1: 'France'}, 'APPROACH': {0: 'MAEU_TEST', 1: 
    'MAEU_TEST'}})
    di = {'France': 'FR',
          'Germany': 'DE',
         }
    
    df
    NATIONALITY APPROACH
    0   Germany MAEU_TEST
    1   France  MAEU_TEST
    

    我的目标是将字典“di”应用于数据帧,并根据“NATIONALITY”列中的值替换“APPROACH”列中子字符串“EU”。例如,如果国籍等于“德国”,则应将“欧盟”替换为“DE”。最终,我的目标是获得以下产出:

    NATIONALITY APPROACH
    0   Germany MADE_TEST
    1   France  MAFR_TEST
    

    到目前为止,我所尝试的是使用loc函数有条件地替换这些值:

    df.loc[df['NATIONALITY']=="Germany", 'APPROACH'] = df['APPROACH'].replace({'EU': 'DE'}, regex=True)
    

    上面的方法很好,但考虑到我有一长串国家,使用字典会更有效率。

    有什么建议吗?提前感谢!

    2 回复  |  直到 3 年前
        1
  •  2
  •   mozway    3 年前

    如果你总是 EU 字符串在一个固定的位置(这里是字符2-3),然后一个简单的 map 字符串串联是最有效的:

    df['APPROACH'] = (df['APPROACH'].str[:2]
                     +df['NATIONALITY'].map(di)
                     +df['APPROACH'].str[4:]
                     )
    

    如果没有,则需要在对上循环,并将字符串替换为 str.replace (或正则表达式):

    df['APPROACH'] = [a.replace('EU', di[n]) for n, a in
                      zip(df['NATIONALITY'], df['APPROACH'])]
    
    # or, with regex
    import re
    
    df['APPROACH'] = [re.sub('EU', di[n], a) for n, a in
                      zip(df['NATIONALITY'], df['APPROACH'])]
    

    注:。如果你知道只有一次 欧盟 ,通过设置最大更换次数来提高效率 a.replace('EU', di[n], 1) )。

    组的备选方案

    如果你有一个给定国籍的多次重复,你可以使用 groupby.transform :

    df['APPROACH'] = (df.groupby('NATIONALITY')['APPROACH']
                        .transform(lambda g: g.str.replace('EU', di[g.name]))
                     )
    

    注:。这应该比列表理解更有效 如果你有大型团体 。在真实数据集上进行测试。

    输出:

      NATIONALITY   APPROACH
    0     Germany  MADE_TEST
    1      France  MAFR_TEST
    
        2
  •  1
  •   keepAlive    3 年前

    还有一种方法是将事件替换为

    >>> di = {'France': 'MAFR_TEST', 'Germany': 'MADE_TEST'}
    >>> df.APPROACH = df.apply(axis=1, func=lambda s: di[s.NATIONALITY])
    >>> df
      NATIONALITY   APPROACH
    0     Germany  MADE_TEST
    1      France  MAFR_TEST
    

    如上所述,这是在国家基础上进行的,如果每个国家有一个以上的方法,这可能会有问题。否则,很简单,你可以

    di = {
        'France': {
            'MAEU_TEST': 'MAFR_TEST'
            # forthcoming other FR approaches
        },
        'Germany': {
            'MAEU_TEST': 'MADE_TEST'
            # forthcoming other DE approaches
        }
    }
    df.APPROACH = df.apply(
        axis=1, func=lambda s: (
            di[s.NATIONALITY].get(s.APPROACH, 'not-found')
        )
    )
    

    返回

      NATIONALITY   APPROACH
    0     Germany  MADE_TEST
    1      France  MAFR_TEST