Pandas使用update合并DataFrame返回None,致to_csv报错的解决方法
问题解决:DataFrame.update导致NoneType错误
问题描述
合并足球赛事数据的archive和df_new两个DataFrame时,执行df_merge = df_merge.update(df_results)后,df_merge变为NoneType,调用to_csv时触发如下错误:
AttributeError: 'NoneType' object has no attribute 'to_csv'
核心原因
Pandas的DataFrame.update()方法是原地修改当前DataFrame,不会返回新的DataFrame对象,它的返回值是None。把这个返回值赋值给df_merge,会直接覆盖原有的DataFrame对象,导致后续调用to_csv时出错。
解决方案
1. 修正update的调用方式
删除赋值操作,直接原地修改:
# 错误写法:df_merge = df_merge.update(df_results) df_merge.update(df_results) # 正确写法,原地修改,不返回新对象
2. 优化合并逻辑(可选)
原合并代码存在冗余,可简化为基于唯一标识的合并逻辑,确保数据匹配更准确:
# 替换原合并代码 df_merge = df_csv.merge(dt, on=['match_date', 'competition', 'team_home', 'team_away', 'match'], how='left') # 合并后处理列名冲突,优先保留新数据填充原空值 for col in ['home_goals', 'away_goals', 'score']: df_merge[col] = df_merge[f'{col}_y'].fillna(df_merge[f'{col}_x']) # 保留原csv的列顺序 df_merge = df_merge[df_csv.columns]
3. 修复数据类型潜在问题
get_result中直接转换int(x['home_goals'])可能因NaN报错,先处理空值:
def get_result(df): df = df[(df['score'].notnull()) & (df['result'].isnull())].copy() # 加copy避免SettingWithCopyWarning # 先填充空值为0,再转int df['home_goals'] = df['home_goals'].fillna(0).astype(int) df['away_goals'] = df['away_goals'].fillna(0).astype(int) df['result'] = df.apply(lambda x: market_result(x['team_home'], x['team_away'], x['tip'], x['home_goals'], x['away_goals']), axis=1) return df
修改后的完整代码
import pandas as pd def market_result(home,away,mkt,hg,ag): if (mkt == f'{home} To Win') and (hg > ag): return 'GREEN' if (mkt == f'{home} To Win') and (hg <= ag): return 'RED' if (mkt == f'{away} To Win') and (ag > hg): return 'GREEN' if (mkt == f'{away} To Win') and (ag <= hg): return 'RED' if (mkt == 'Both Teams To Score') and (hg > 0) and (ag > 0): return 'GREEN' if (mkt == 'Both Teams To Score') and ((hg == 0) or (ag == 0)): return 'RED' if (mkt == 'Both Teams To Score - No') and ((hg == 0) or (ag == 0)): return 'GREEN' if (mkt == 'Both Teams To Score - No') and ((hg > 0) or (ag > 0)): return 'RED' if (mkt == 'Under 2.5 Goals') and (hg+ag < 2.5): return 'GREEN' if (mkt == 'Under 2.5 Goals') and (hg+ag >= 2.5): return 'RED' if (mkt == 'Over 2.5 Goals') and (hg+ag > 2.5): return 'GREEN' if (mkt == 'Over 2.5 Goals') and (hg+ag <= 2.5): return 'RED' if (mkt == 'Under 3.5 Goals') and (hg+ag < 3.5): return 'GREEN' if (mkt == 'Under 3.5 Goals') and (hg+ag >= 3.5): return 'RED' if (mkt == 'Over 3.5 Goals') and (hg+ag > 3.5): return 'GREEN' if (mkt == 'Over 3.5 Goals') and (hg+ag <= 3.5): return 'RED' def get_result(df): df = df[(df['score'].notnull()) & (df['result'].isnull())].copy() df['home_goals'] = df['home_goals'].fillna(0).astype(int) df['away_goals'] = df['away_goals'].fillna(0).astype(int) df['result'] = df.apply(lambda x: market_result(x['team_home'], x['team_away'], x['tip'], x['home_goals'], x['away_goals']), axis=1) return df def append_matches(archive,df_new): df_csv = pd.read_csv(archive) # 处理空字符串为NaN df_csv = df_csv.replace('', pd.NA) dt = pd.read_csv(df_new) # 简化合并逻辑 df_merge = df_csv.merge(dt, on=['match_date', 'competition', 'team_home', 'team_away', 'match'], how='left') # 合并后填充数据 for col in ['home_goals', 'away_goals', 'score']: df_merge[col] = df_merge[f'{col}_y'].fillna(df_merge[f'{col}_x']) # 保留原csv的列顺序 df_merge = df_merge[df_csv.columns] df_results = get_result(df_merge) # 直接原地更新,不赋值 df_merge.update(df_results) df_merge.to_csv(archive, index=False) def main(): append_matches('archive.csv','df_new.csv') if __name__ == '__main__': main()
内容的提问来源于stack exchange,提问作者Digital Farmer
相关产品推荐
相关产品推荐

