根据映射表拆分Pandas DataFrame时遇'unhashable type: list'错误求助
问题描述
我有一个包含200+列的客户数据DataFrame(df),其中包含CAMPAIGN_ID列;另有映射表mapping_csv,记录每个CAMPAIGN_ID对应的需提取列列表。我需要按CAMPAIGN_ID拆分df,为每个campaign生成仅包含对应映射列的CSV文件,但运行代码时触发「TypeError: unhashable type: 'list'」错误。
尝试的代码如下:
for campaign in df['CAMPAIGN_ID'].unique(): df2 = df[df['CAMPAIGN_ID']==campaign] # remove blank columns df2.dropna(how='all', axis=1, inplace=True) for column in df2.columns: if df2[column].unique()[0]=="0000-00-00" and df2[column].unique().shape[0]==1: df2 = df2.drop(column, axis=1) for column in df2.columns: if df2[column].unique()[0]=='0' and df2[column].unique().shape[0]==1: df2 = df2.drop(column, axis=1) # select required columns df2 = df2[mapping_csv.loc[mapping_csv['CAMPAIGN_ID']==campaign, 'Variable_List'].str.replace(" ","").str.split(",")] file_shape = df2.shape[0] filename = "cart_"+str(dt.date.today().strftime('%Y%m%d'))+"_"+campaign+"_rowcnt_"+str(file_shape) df2.to_csv(filename+".csv",index=False)
错误原因
报错「TypeError: unhashable type: 'list'」是因为mapping_csv.loc[mapping_csv['CAMPAIGN_ID']==campaign, 'Variable_List'].str.replace(" ","").str.split(",")返回的是包含列表元素的Series对象,而DataFrame索引列时需要的是可哈希的一维列表/数组,直接用这个Series索引就会触发错误。
修正方案
需要把提取到的列列表从Series中取出,确保是一维列表类型;同时可以提前预处理映射表,避免循环内重复计算,还能优化空列删除逻辑。
修正后的代码:
import pandas as pd import datetime as dt # 提前预处理映射表,转成字典快速查找 mapping_csv['Variable_List'] = mapping_csv['Variable_List'].str.replace(" ", "").str.split(",") campaign_cols_map = mapping_csv.set_index('CAMPAIGN_ID')['Variable_List'].to_dict() for campaign in df['CAMPAIGN_ID'].unique(): # 筛选当前campaign数据,用copy避免链式赋值警告 df2 = df[df['CAMPAIGN_ID'] == campaign].copy() # 批量筛选需要删除的列:空列、全为"0000-00-00"、全为"0"的列 drop_cols = [] for col in df2.columns: unique_vals = df2[col].unique() if (df2[col].isna().all() or (len(unique_vals) == 1 and unique_vals[0] == "0000-00-00") or (len(unique_vals) == 1 and unique_vals[0] == '0')): drop_cols.append(col) df2.drop(drop_cols, axis=1, inplace=True) # 获取当前campaign的目标列,过滤df2中不存在的列 target_cols = campaign_cols_map.get(campaign, []) valid_cols = [col for col in target_cols if col in df2.columns] if valid_cols: df2 = df2[valid_cols] row_count = df2.shape[0] filename = f"cart_{dt.date.today().strftime('%Y%m%d')}_{campaign}_rowcnt_{row_count}" df2.to_csv(f"{filename}.csv", index=False) else: print(f"Campaign {campaign} 无匹配有效列,跳过导出")
关键改进点
- 提前将映射表转为字典,减少循环内重复计算,提升运行效率
- 合并列删除逻辑为一次循环,减少对DataFrame列的遍历次数
- 确保目标列是一维列表,避免Series引发的哈希错误
- 添加列存在性检查,避免因映射列不存在触发KeyError
- 使用f-string格式化字符串,代码更简洁易读
内容的提问来源于stack exchange,提问作者Prasanjit
相关产品推荐
相关产品推荐

