为何不同Pandas DataFrame中相同邮箱地址的哈希值不同?
问题
在使用Pandas处理数据时,对两个DataFrame(df1和df2)中的邮箱地址列进行哈希操作,随后将两个DataFrame按ID进行内连接,发现相同的邮箱地址对应的哈希值却不相同。
复现代码
import pandas as pd ### Boring part to import the data ### # define table 1 as df1 df1 = pd.DataFrame([[2, 'random.email@fjjd.com'], [6, 'different.email@u8888ueend.dskjs'], [7, 'random.email@dsju.c'], [8, 'same.email@dkicj.c'], [200, 'different.email@cjhs.oo'], [18, 'random.email@siidjd.dd'], [19, 'random.email@dsjds.j']]) df1 = df1.set_axis(['ID1', 'email 1'], axis=1) # define table 2 as df2 df2 = pd.DataFrame([[100, 'new.email@jsscd.d'], [6, 'different.email@uueend.dskjs'], [99, 'new.email@djjsd.conm'], [10, 'new.email@jhhs.co'], [115, 'new.email@dsjjdsds.cod'], [116, 'new.email@dsjkjds.ckk'], [8, 'same.email@dkicj.c'], [200, 'different.email@jdsjd.co']]) df2 = df2.set_axis(['ID2', 'email 2'], axis=1) ### End part to import the data ### ### Fun part now... ### # hash the emails in each row of df1? df1['hash 1'] = pd.util.hash_pandas_object(df1['email 1'].astype(str)) # hash the emails in each row of df2? df2['hash 2'] = pd.util.hash_pandas_object(df2['email 2'].astype(str)) # perform an inner join of df1 and df2 about their IDs, ID1 and ID2 respectively df3 = pd.merge(df1, df2, how='inner', left_on='ID1', right_on='ID2') # add an email comparison column df3['same email'] = df3['email 1'] == df3['email 2'] # add a hash comparison column df3['same hash'] = df3['hash 1'] == df3['hash 2'] # print the table... print(df3)
执行结果
ID1 email 1 hash 1 ID2 email 2 hash 2 same email same hash 0 6 different.email@u8888ueend.dskjs 18381560226251184406 6 different.email@uueend.dskjs 16113553761483526335 False False 1 8 same.email@dkicj.c 5780217243550696535 8 same.email@dkicj.c 6939369575697951555 True False 2 200 different.email@cjhs.oo 13252009090739560311 200 different.email@jdsjd.co 1942861278265138167 False False
可见ID=8的行中邮箱地址完全相同,但对应的哈希值却不一致。
原因与解决方法
问题根源
你误用了哈希函数:pd.util.hash_pandas_object() 的作用是对整个Pandas对象(比如Series)生成一个整体哈希值,而非对Series内的每个元素单独哈希。当你将这个函数的结果赋值给新列时,Pandas会把单一哈希值广播到整列所有行,不同Series(即便包含相同元素)的整体哈希值自然不同,导致相同邮箱的哈希结果不一致。
正确做法
要对每个邮箱字符串单独哈希,需使用Python内置hash()函数,或更稳定的加密哈希函数(如hashlib中的MD5/SHA256)。以下是修正后的代码:
方法1:使用Python内置hash()
import pandas as pd # 数据导入部分不变... # 对每个邮箱单独哈希 df1['hash 1'] = df1['email 1'].astype(str).apply(hash) df2['hash 2'] = df2['email 2'].astype(str).apply(hash) # 后续连接、对比代码不变 df3 = pd.merge(df1, df2, how='inner', left_on='ID1', right_on='ID2') df3['same email'] = df3['email 1'] == df3['email 2'] df3['same hash'] = df3['hash 1'] == df3['hash 2'] print(df3)
方法2:使用加密哈希(跨会话/环境一致)
内置hash()的结果受Python会话影响,不同会话可能得到不同结果。若需要稳定的哈希值,推荐使用hashlib:
import pandas as pd import hashlib def str_hash(s): # 将字符串转为字节,计算SHA256哈希后转为十六进制字符串 return hashlib.sha256(s.encode('utf-8')).hexdigest() # 数据导入部分不变... df1['hash 1'] = df1['email 1'].astype(str).apply(str_hash) df2['hash 2'] = df2['email 2'].astype(str).apply(str_hash) # 后续连接、对比代码不变 df3 = pd.merge(df1, df2, how='inner', left_on='ID1', right_on='ID2') df3['same email'] = df3['email 1'] == df3['email 2'] df3['same hash'] = df3['hash 1'] == df3['hash 2'] print(df3)
修正后结果
两种方法都会让ID=8的行中,相同邮箱的哈希值完全一致,same hash列会显示True。
内容的提问来源于stack exchange,提问作者BieberFantasy
相关产品推荐
相关产品推荐

