pandas合并DataFrame与CSV去重报unhashable list错解决方法
问题原因
drop_duplicates抛出unhashable list错误和DataFrame是否由字典列表构造无关,核心原因是某列/某几列中存储了list类型的值:list是可变类型不可哈希,pandas去重时需要计算值的哈希值做比对,遇到list就会触发该报错。
这类问题基本都是API返回的嵌套字段(比如对局掉落道具列表、对局参与玩家ID列表等)未做序列化处理,直接以原始list结构存入DataFrame导致的。
实现方案
- 先预处理所有包含list的列,将list转为可哈希的元组或字符串,从根源解决哈希报错。如果后续需要解析嵌套结构就转元组,不需要保留结构直接转字符串即可。
- 去重优先使用数据自带的唯一标识字段(比如对局ID、记录流水号)作为比对依据,比全字段比对效率高,也不会因为浮点精度、字段值微小偏差导致去重失效。没有唯一标识时再走全字段去重。
- 首次运行时目标CSV不存在,直接写入首批拉取的100条数据即可;后续运行只追加历史数据中不存在的新条目,不需要每次全量重写文件,IO性能更好。
参考代码
import pandas as pd import os SAVE_PATH = 'StatTracker.csv' # 加载本次拉取的新批次数据 df_new = pd.DataFrame(statsTableList) # 预处理含list的列,解决不可哈希报错 for col in df_new.columns: if df_new[col].apply(lambda x: isinstance(x, list)).any(): # 需要保留嵌套结构转tuple即可,不需要直接用str()转字符串 df_new[col] = df_new[col].apply(tuple) # 首次运行直接写入初始数据 if not os.path.exists(SAVE_PATH): df_new.to_csv(SAVE_PATH, index=False) else: # 读取历史存储数据 df_history = pd.read_csv(SAVE_PATH) # 同步新数据格式:CSV读入的序列化元组会自动转字符串,要和历史格式对齐才能准确去重 for col in df_new.columns: if df_new[col].apply(lambda x: isinstance(x, tuple)).any(): df_new[col] = df_new[col].apply(str) # 有唯一主键就把主键列名传给subset参数,比如subset=['match_id'],无主键则去掉subset走全字段匹配 df_append = df_new[~df_new.isin(df_history.to_dict('list')).all(axis=1)] # 追加写入新数据,不重复写表头、不写入索引 df_append.to_csv(SAVE_PATH, mode='a', header=False, index=False)
注意:如果习惯用
concat+drop_duplicates的写法,只要完成上述列类型预处理,原有写法就可以正常运行,不会再触发unhashable报错,两种去重逻辑最终效果一致。
内容的提问来源于stack exchange,提问作者Skye Peterson
相关产品推荐
相关产品推荐

