基于另一DataFrame删除Pandas DataFrame行中Series类型ID值的问题
我有两个Pandas DataFrame:mydf1包含5个属性,其中id是Pandas Series类型,创建代码如下:
import numpy as np import pandas as pd mydf1=pd.DataFrame(columns=['group','id','name','mail','gender']) data = np.array([2540948, 2540955, 2540956,2540956,7138932]) x=pd.Series(data) mydf1.loc[0]=[1,x,'abc','abc@xyz.com','male']
mydf2包含group和id属性,id同样为Series类型,创建代码:
mydf2=pd.DataFrame(columns=['group','id']) data1 = np.array([2540948, 2540955, 2540956]) y=pd.Series(data1) mydf2.loc[0]=[1,y]
实际数据的行数和Series长度都比较大,我的需求是:匹配group后,删除mydf1中存在于mydf2的id值(比如示例处理后group1的id应该剩余2540956,7138932)。
尝试执行counts = mydf1.groupby('id').cumcount()时,出现了TypeError: 'Series' objects are mutable, thus they cannot be hashed错误,请求解决方法。
错误原因分析
你遇到的TypeError是因为mydf1的id列中每个元素都是可变的Series对象,而Pandas的groupby操作要求分组键必须是可哈希的类型(比如整数、字符串等),可变对象无法被哈希,所以会抛出这个错误。
要解决你的需求,首先需要把这种“单元格嵌套Series”的结构展开成常规的行结构,再进行匹配和过滤。
步骤1:展开嵌套的Series为多行
使用Pandas的explode()方法,可以把每个单元格中的Series元素拆分成单独的行,同时保留对应的group、name等其他属性:
# 展开mydf1的id列 mydf1_exploded = mydf1.explode('id', ignore_index=True) # 展开mydf2的id列 mydf2_exploded = mydf2.explode('id', ignore_index=True)
展开后,mydf1_exploded会变成5行,每行对应一个id值;mydf2_exploded变成3行,每行对应一个id值。
步骤2:确定需要删除的(group, id)组合
提取mydf2中所有需要排除的group和id组合:
to_remove = mydf2_exploded[['group', 'id']].drop_duplicates()
步骤3:过滤mydf1中的目标id
使用merge()结合_merge标识,筛选出mydf1中不在to_remove里的行:
# 左连接并标记来源 merged = mydf1_exploded.merge(to_remove, on=['group', 'id'], how='left', indicator=True) # 只保留mydf1独有的行 mydf1_filtered_exploded = merged[merged['_merge'] == 'left_only'].drop(columns='_merge')
此时mydf1_filtered_exploded的内容就是你需要的过滤后的数据,每行对应一个保留的id值:
| group | id | name | gender | |
|---|---|---|---|---|
| 1 | 2540956 | abc | abc@xyz.com | male |
| 1 | 7138932 | abc | abc@xyz.com | male |
步骤4(可选):恢复嵌套Series结构
如果需要把过滤后的id重新组合成原来的Series结构,可以用groupby+apply(pd.Series):
mydf1_final = mydf1_filtered_exploded.groupby(['group', 'name', 'mail', 'gender'])['id'].apply(pd.Series).reset_index() # 重命名列名(如果需要) mydf1_final = mydf1_final.rename(columns={'id': 'id_series'})
这样就得到了和原始结构一致,但id已经过滤后的DataFrame。
验证结果
示例中处理后,group1的id确实剩余2540956和7138932,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Tanvi Mirza

