【问题标题】:Retain strings in a column using a dictionary's value使用字典的值保留列中的字符串
【发布时间】:2022-11-24 10:25:53
【问题描述】:

我想根据字典的键和值保留具有最大值的字符串。对如何有效地做到这一点有什么建议吗?

fruit_dict = {
  "Apple": 10,
  "Watermelon": 20,
  "Cherry": 30
}

df = pd.DataFrame(
    {
        "ID": [1, 2, 3, 4, 5],
        "name": [
            "Apple, Watermelon",
            "Cherry, Watermelon",
            "Apple",
            "Cherry, Apple",
            "Cherry",
        ],
    }
)

   ID                name
0   1   Apple, Watermelon
1   2  Cherry, Watermelon
2   3               Apple
3   4       Cherry, Apple
4   5              Cherry

预期输出:

   ID        name
0   1  Watermelon
1   2      Cherry
2   3       Apple
3   4      Cherry
4   5      Cherry

【问题讨论】:

  • 如果每个组的所有值都不匹配,会发生什么情况?
  • 我正在考虑将它们的值分配为 0,但接下来的挑战是,如果它们没有在 dict 中获得匹配的键,那么解决方案是否会遇到问题?我可以做的一件事是在我的其他问题中使用你的一个答案来首先过滤它,但如果我们有一个字符串与字典不匹配,那是不理想的。 @jezrael

标签: python pandas


【解决方案1】:

一种使用 applymaxfruit_dict.get 作为键的方法:

new_df = (df.assign(name=df['name'].str.split(', ')
            .apply(lambda l: max(l, key=fruit_dict.get)))
          )

或者,如果您希望字典中缺少某些名称:

new_df = (df.assign(name=df['name'].str.split(', ')
            .apply(lambda l: max(l, key=lambda x: fruit_dict.get(x, float('-inf'))))
          )

输出:

   ID        name
0   1  Watermelon
1   2      Cherry
2   3       Apple
3   4      Cherry
4   5      Cherry

【讨论】:

  • 嘿@mozway,我真的很喜欢字典中缺少名称的解决方案。我测试了边缘情况,效果很好!
  • @codedancer 不客气,如果你有一个大数据集,你可以测试这个解决方案和@jezrael 的混合解决方案:df['name'].apply(lambda x: max(x.split(', '), key=lambda x: fruit_dict.get(x, float('-inf')))),我希望这会更快;)
  • @jezrael 我想得太晚了;)
  • @mozway - 测试边缘状态并总是在我的回答中首先返回不匹配的值
【解决方案2】:

利用:

df = (df.assign(name= df['name'].str.split(', '))
        .explode('name')
       .assign(new = lambda x: x['name'].map(fruit_dict))
        .sort_values(['ID', 'new'], ascending=[True, False])
        .drop_duplicates('ID')
       )
print (df)
   ID        name  new
0   1  Watermelon   20
1   2      Cherry   30
2   3       Apple   10
3   4      Cherry   30
4   5      Cherry   30

或者:

df['new'] = df['name'].apply(lambda x: max(x.split(', '), key=fruit_dict.get))
print (df)
   ID                name         new
0   1   Apple, Watermelon  Watermelon
1   2  Cherry, Watermelon      Cherry
2   3               Apple       Apple
3   4       Cherry, Apple      Cherry
4   5              Cherry      Cherry

编辑:如果没有匹配项返回第一个值:

fruit_dict = {
  "Apple": 10,
  "Watermelon": 20,
  "Cherry": 30
}

df = pd.DataFrame(
    {
        "ID": [1, 2, 3, 4, 5],
        "name": [
            "Apple, Watermelon",
            "Cherry, Watermelon",
            "Apple",
            "Cherry, Apple",
            "ooo, Cherry2, aaaa", <- changed data
        ],
    }
)
print (df)

df1 = (df.assign(name= df['name'].str.split(', '))
        .explode('name')
       .assign(new = lambda x: x['name'].map(fruit_dict))
        .sort_values(['ID', 'new'], ascending=[True, False])
        .drop_duplicates('ID')
       )
print (df1)
   ID        name   new
0   1  Watermelon  20.0
1   2      Cherry  30.0
2   3       Apple  10.0
3   4      Cherry  30.0
4   5         ooo   NaN

如果不匹配则需要NaNs:

df1['name'] = df1['name'].mask(df1.pop('new').isna())
print (df1)
   ID        name
0   1  Watermelon
1   2      Cherry
2   3       Apple
3   4      Cherry
4   5         NaN

df['new1'] = df['name'].apply(lambda x: max(x.split(', '), key=lambda x: fruit_dict.get(x, float('-inf'))))

df['new2'] = df['name'].apply(lambda x: max(x.split(', '), key=lambda x: fruit_dict.get(x, 0)))

df['new3'] = df['name'].apply(lambda x: max(x.split(', '), key=lambda x: fruit_dict.get(x, 1000)))

print (df)
   ID                name        new1        new2        new3
0   1   Apple, Watermelon  Watermelon  Watermelon  Watermelon
1   2  Cherry, Watermelon      Cherry      Cherry      Cherry
2   3               Apple       Apple       Apple       Apple
3   4       Cherry, Apple      Cherry      Cherry      Cherry
4   5  ooo, Cherry2, aaaa         ooo         ooo         ooo

【讨论】:

    【解决方案3】:
    fruit_dict = {
        "Apple": 10,
        "Watermelon": 20,
        "Cherry": 30
    }
    
    df.assign(name=df.name.str.split(',')).name.map(lambda x:pd.Series(fruit_dict)[x].nlargest().index.values[0])
    
    0    Watermelon
    1        Cherry
    2         Apple
    3        Cherry
    4        Cherry
    Name: name, dtype: object
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-15
      • 2022-12-11
      相关资源
      最近更新 更多