python - 如何生成8位唯一标识符以替换python pandas中的现有标识符
问题描述
假设我有以下简单的数据框。但实际上,我有数十万行这样的行。
df
ID Sales
倀굖곾ꆹ譋῾理 100
倀굖곾ꆹ 50
倀굖곾ꆹ譋῾理 70
곾ꆹ텊躥㫆 60
我的想法是我想用随机生成的 8 位数字替换中文数字,如下所示。
ID Sales
13434535 100
67894335 50
13434535 70
10986467 60
数字是随机生成的,但它们也应保持唯一性。例如,第 0 行和第 2 行相同,当它被随机唯一 ID 替换时,它也应该相同。
任何人都可以在 Python 熊猫中帮助解决这个问题吗?任何以前已经完成的解决方案也是受欢迎的。
解决方案
这里的主要方法是使用Series.map()
“ID”来分配新值。
用于将 Series 中的每个值替换为另一个值,该值可以从函数 a
dict
或 a派生Series
。
这正是您正在寻找的。
以下是生成新 ID的一些选项:
1.随机生成的8位整数,如题
您可以首先使用数据框中的每个唯一 ID创建一个随机生成的 8 位整数的映射。然后Series.map()
在“ID”上使用以重新分配新值。我已经包含了一个while
循环来确保生成的 ID 是唯一的。
import random
original_ids = df['ID'].unique()
while True:
new_ids = {id_: random.randint(10_000_000, 99_999_999) for id_ in original_ids}
if len(set(new_ids.values())) == len(original_ids):
# all the generated id's were unique
break
# otherwise this will repeat until they are
df['ID'] = df['ID'].map(new_ids)
输出:
ID Sales
0 91154173 100
1 27127403 50
2 91154173 70
3 55892778 60
编辑和警告:原始ID是汉字,它们已经长度为8。肯定有10多个汉字,所以如果原始ID组合错误,可能无法为新集合制作足够唯一的8位ID . 除非您受内存限制,否则我建议使用 16-24 位数字。或者甚至更好...
2. 使用UUID。[理想的]
您仍然可以使用 ID 的“整数”版本而不是十六进制。这具有不需要检查唯一性的额外好处:
import uuid
original_ids = df['ID'].unique()
new_ids = {cid: uuid.uuid4().int for cid in original_ids}
df['ID'] = df['ID'].map(new_ids)
(如果您对十六进制 id 没问题,请将uuid.uuid4().int
上面更改为uuid.uuid4().hex
。)
输出:
ID Sales
0 10302456644733067873760508402841674050 100
1 99013251285361656191123600060539725783 50
2 10302456644733067873760508402841674050 70
3 112767087159616563475161054356643068804 60
2.B。来自 UUID 的较小数字
如果上面生成的 ID 太长,您可以将其截断,但风险较小。在这里,我只使用前 16 个十六进制字符并将它们转换为 int。您可以将其放在上面对选项 1 所做的唯一性循环检查中。
import uuid
original_ids = df['ID'].unique()
DIGITS = 16 # number of hex digits of the UUID to use
new_ids = {cid: int(uuid.uuid4().hex[:DIGITS], base=16) for cid in original_ids}
df['ID'] = df['ID'].map(new_ids)
输出:
ID Sales
0 14173925717660158959 100
1 10599965012234224109 50
2 14173925717660158959 70
3 13414338319624454663 60
3.根据实际值创建映射:
这组选项具有以下优点:
- 不需要唯一性检查,因为它确定性地基于原始 ID 和
- 因此,相同的原始 ID 将生成相同的新 ID
- 不需要预先创建的地图
3.A. CRC32
(与上面的选项 2.B. 相比,发现具有不同 ID 的冲突的可能性更高。)
import zlib
df['ID'] = df['ID'].map(lambda cid: zlib.crc32(bytes(cid, 'utf-8')))
输出:
ID Sales
0 2083453980 100
1 1445801542 50
2 2083453980 70
3 708870156 60
3.B。Python内置hash()
的原始ID【我在这个场景中的首选方法】
- 可以一行完成,无需导入
- 相当安全,不会为不同的 ID 产生冲突
df['ID'] = df['ID'].map(hash)
输出:
ID Sales
0 4663892623205934004 100
1 1324266143210735079 50
2 4663892623205934004 70
3 6251873913398988390 60
3.C。MD5Sum,或任何来自hashlib
由于 ID 预计很小(8 个字符),即使使用 MD5,发生冲突的概率也非常低。
import hashlib
DIGITS = 16 # number of hex digits of the hash to use
df['ID'] = df['ID'].str.encode('utf-8').map(lambda x: int(hashlib.md5(x).hexdigest()[:DIGITS], base=16))
输出:
ID Sales
0 17469287633857111608 100
1 4297816388092454656 50
2 17469287633857111608 70
3 11434864915351595420 60
推荐阅读
- sql - SQL - GROUP BY 所有可能的变量
- bash - bash,在管道中获取退出状态
- amazon-web-services - 如何仅在将特定文件(密钥)写入 S3 存储桶时触发 AWS 事件规则
- c# - 使用 ASP .NET MVC 读取和写入 cookie 的错误
- git - 如何提交在此存储库之外进行的 Git 存储库的重大更改?
- react-native - 更新节点后纱线安装不起作用
- c# - UWP 在开始时设置为最大化视图似乎不起作用
- php - str_getcsv 分隔行删除行中的封闭字符
- java - 如何使用 thymeleaf 设置对象字段
- hibernate - 如何将 Java 类型全局映射到 UserTypes 和数据库类型?