如何在Python DataFrame中比较子串生成对手信息新列?
首先明确你的需求:从格式为SAC@HOU 12/09/2019 08:00PM ET的Game Info列中,结合当前球队的Team列,生成存储对手球队的Opp列。咱们先拆解你之前代码的报错原因,再给出可行的解决方案。
为什么之前的方法会报错?
第一种方法的问题
你尝试用df['Game Info'].str[:3].str.contains(df['Team'])做判断,但str.contains()的参数需要是单个字符串/正则表达式,而你传入的是一个Series(df['Team'])——Series是可变对象无法被哈希,所以触发了'Series' objects are mutable, thus they cannot be hashed错误。另外df["Opp"][df['Opp'].empty]的逻辑也不对:df['Opp'].empty是判断整个列是否为空,不是逐行判断当前值是否为空。
第二种方法的问题
np.where的语法写错了(括号位置混乱),而且直接用if df['Team'].str != df['Game Info'].str[:3] else ...会触发The truth value of a Series is ambiguous错误——因为if需要单个布尔值,但你给出的是一整列布尔值,Python无法确定用哪个值来做判断。
正确的解决方案
这里优先推荐向量化操作(比逐行apply效率更高),提供三种不同思路的写法:
方法一:拆分球队后用np.where判断
先从Game Info中拆分出主客场球队,再通过np.where判断当前球队属于哪一方,取另一方作为对手:
import numpy as np # 拆分出客场球队(@前的3个字符)和主场球队(@后的前3个字符) df['away_team'] = df['Game Info'].str.split('@').str[0] df['home_team'] = df['Game Info'].str.split('@').str[1].str[:3] # 用np.where判断:如果当前球队是客场,对手就是主场;反之则是客场 df['Opp'] = np.where(df['Team'] == df['away_team'], df['home_team'], df['away_team']) # 不需要临时列的话可以删掉 df = df.drop(['away_team', 'home_team'], axis=1)
方法二:用str.extract提取球队对,再替换当前球队
先提取Game Info开头的球队对(比如SAC@HOU),然后把当前球队从这个字符串中去掉,剩下的就是对手:
# 提取开头的球队对(格式为AAA@BBB) df['team_pair'] = df['Game Info'].str.extract(r'^(\w{3}@\w{3})') # 逐行替换当前球队,去掉@和空字符得到对手 df['Opp'] = df.apply(lambda x: x['team_pair'].replace(x['Team'], '').replace('@', '').strip(), axis=1) # 删除临时列 df = df.drop('team_pair', axis=1)
方法三:简洁的一行向量化写法
如果不想生成临时列,可以直接用np.where结合字符串切片完成:
df['Opp'] = np.where( df['Team'] == df['Game Info'].str[:3], df['Game Info'].str[4:7], df['Game Info'].str[:3] )
这个逻辑很直观:如果当前球队是Game Info开头的3个字符(客场),对手就是@后的3个字符;否则对手就是开头的3个字符。
内容的提问来源于stack exchange,提问作者bballboy8

