【问题标题】:Pandas: change value based on multiple conditions of different typePandas:根据不同类型的多个条件更改值
【发布时间】:2022-01-20 14:56:22
【问题描述】:

我正在尝试制作一个 Champions League Fantasy 统计表,并且我从 2 个不同的网站获取数据,这些网站的球员名称彼此之间略有不同。

我有来自站点 1 的 df1

                name     age       team skill  cost  gls  ast
0       Lionel Messi  34-175      Paris     4  11.3    5    0
1   Ryan Gravenberch  19-214       Ajax     3   6.2    0    0
2     Junior Messias  30-217      Milan     3   6.5    1    0
3  Kepa Arrizabalaga  27-074    Chelsea     1   5.0    0    0
4     Kenneth Taylor  19-214       Ajax     3   5.0    0    0
5            Alisson  30-320  Liverpool     1   6.1    0    0

还有来自站点 2 的 df2

      name     age       team  gls  ast
0     Kepa  27-074    Chelsea    0    0
1   Lionel  34-175      Paris    5    0
2   Junior  30-217      Milan    1    0
3  Kenneth  19-214       Ajax    0    0
4   Neymar  29-314      Paris    0    0
5     Ryan  19-214       Ajax    0    0

我的目标是根据多个条件匹配名称:

  • 年龄(df2 中的字符串等于df1 中的字符串)
  • 团队(df2 中的字符串等于df1 中的字符串)
  • 名称(df2 中的字符串包含df1 中的字符串中)

我想将名字作为最后一个条件传递的原因是因为有两名球员在同一天出生并为同一支球队效力,比如肯尼斯·泰勒和瑞恩·格雷文伯奇

我在想这样的事情:

df2.loc[(df2['team'] == df1['team']) & (df2['age'] == df1['age']) & (df2['name'].str.contains(df1['name'].str)), 'name'] = df1['name']

但我收到此错误:

TypeError: 'Series' objects are mutable, thus they cannot be hashed

df2 的期望输出是:

                name     age     team  gls  ast
0  Kepa Arrizabalaga  27-074  Chelsea    0    0
1       Lionel Messi  34-175    Paris    5    0
2     Junior Messias  30-217    Milan    1    0
3     Kenneth Taylor  19-214     Ajax    0    0
4             Neymar  29-314    Paris    0    0
5   Ryan Gravenberch  19-214     Ajax    0    0

df2 中与条件匹配的所有名称都替换为 df1 中的名称

【问题讨论】:

  • 在期望的输出中Kepa不应该是Kepa Arrizabalaga吗?
  • 不,因为我想要 df1 中的所有名称
  • 但是按照前面提到的匹配规则,df2 中的字符串并没有严格包含在 df1 中。除非您的意思是检查两个字符串中较短的一个是否包含在另一个字符串中?
  • 无论如何我已经修改了我的答案以考虑这两种情况,看看它是否适合你
  • 您的代码出现了另一个错误。 "TypeError: 第一个参数必须是字符串或编译模式"

标签: python pandas dataframe jupyter-notebook


【解决方案1】:

(i) 在ageteam 上将df2 从右侧合并到df1

(ii) 将df2 中但不在df1 中的名称分配给df1(即name_x)的name 列。

(iii) 过滤掉在name_xname_y 列中不匹配的名称并删除name_y

df3 = df1[['name','age','team']].merge(df2, on=['age','team'], how='right')
mask = pd.isna(df3['name_x'])
df3.loc[mask,'name_x'] = df3.loc[mask,'name_y'].to_numpy()
df3 = df3[df3.apply(lambda x: x['name_y'] in x['name_x'], axis=1)].drop('name_y', axis=1)

输出:

              name_x     age     team  gls  ast
0  Kepa Arrizabalaga  27-074  Chelsea    0    0
1       Lionel Messi  34-175    Paris    5    0
2     Junior Messias  30-217    Milan    1    0
4     Kenneth Taylor  19-214     Ajax    0    0
5             Neymar  29-314    Paris    0    0
6   Ryan Gravenberch  19-214     Ajax    0    0

【讨论】:

    【解决方案2】:

    试试merge:

    matches = df2.merge(df1[["name", "age", "team"]],
                        on=["age", "team"],
                        how="left")
    matches["name_y"] = matches["name_y"].fillna(matches["name_x"])
    matches = matches.where(matches.apply(lambda x: x["name_x"] in x["name_y"], axis=1)).dropna()
    output = matches.drop("name_x", axis=1).rename(columns={"name_y": "name"}).reindex(df2.columns, axis=1)
    
    >>> output
                     name     age     team  gls  ast
    0  Kepa Arrizabalaga  27-074  Chelsea  0.0  0.0
    1       Lionel Messi  34-175    Paris  5.0  0.0
    2     Junior Messias  30-217    Milan  1.0  0.0
    4     Kenneth Taylor  19-214     Ajax  0.0  0.0
    5             Neymar  29-314    Paris  0.0  0.0
    6   Ryan Gravenberch  19-214     Ajax  0.0  0.0
    

    【讨论】:

    • 感谢您的回答,这里的问题是我想检查 df2 中的名称是否包含在 df1 中的原因是因为有可能两个玩家共享生日和团队,所以我会通过他们名称作为最后一个过滤器,并且使用您的解决方案,该问题仍然存在
    • 不确定您的确切意思。我编辑包含fillna,但如果这不起作用,您应该更新您的问题以包含边缘情况。
    • 我更新了我的问题,以防你想出一些解决方案:)
    • @IvánDíazdeLeón - 已编辑!
    【解决方案3】:

    使用它来获得您想要的答案。无需再根据名称单独条件。

    df2.loc[(df2['team'] == df1['team']) & (df2['gls'] == df1['gls']), 'name'] = df1['name']
    

    【讨论】:

    • 很遗憾这是个问题,阿贾克斯有两名球员的年龄完全一样,我会更新我的问题以澄清,谢谢你的回答
    • 我已经编辑了问题以使其尽可能清晰:)
    猜你喜欢
    • 2021-03-02
    • 2014-10-09
    • 2022-01-25
    • 2021-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 2021-09-11
    相关资源
    最近更新 更多