Pandas:根据不同类型的多个条件更改值
Posted
技术标签:
【中文标题】Pandas:根据不同类型的多个条件更改值【英文标题】:Pandas: change value based on multiple conditions of different type 【发布时间】: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: 第一个参数必须是字符串或编译模式"
【参考方案1】:
(i) 在age
和team
上将df2
从右侧合并到df1
。
(ii) 将df2
中但不在df1
中的名称分配给df1
(即name_x
)的name
列。
(iii) 过滤掉在name_x
和name_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']
【讨论】:
很遗憾这是个问题,阿贾克斯有两名球员的年龄完全一样,我会更新我的问题以澄清,谢谢你的回答 我已经编辑了问题以使其尽可能清晰:)以上是关于Pandas:根据不同类型的多个条件更改值的主要内容,如果未能解决你的问题,请参考以下文章