首页 > 解决方案 > 如何生成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 熊猫中帮助解决这个问题吗?任何以前已经完成的解决方案也是受欢迎的。

标签: pythonpandasrandom

解决方案


这里的主要方法是使用Series.map()“ID”来分配新值。

用于将 Series 中的每个值替换为另一个值,该值可以从函数 adict或 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

推荐阅读