提问人:mjoy 提问时间:1/7/2023 更新时间:1/7/2023 访问量:66
创建随机生成的唯一字母列到 pandas 数据帧?
Create column of unique randomly generated letters to pandas dataframe?
问:
我有一个数据框,其中有一列随机字母和数字,然后是一列需要添加到第一列随机字符串中的随机字母/数字的列。像这样,但我的数据帧是 3+ 百万行:
id missing
XK39J 4
NI94N 4
9IN3 5
MN83D 4
IUN2 5
我正在使用以下代码来生成新的随机序列:
def id_generator(size, chars=string.ascii_uppercase + string.digits):
return ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(size))
data['new_id'] = data['missing'].apply(lambda x: id_generator(size = x))
data['final_id'] = data['id'] + data['new_id']
但是,当我使用它时,我最终会在“final_id”列中得到几个重复的值。但是,我需要“final_id”列中的每个值都是唯一的。喜欢:
id missing new_id final_id
XK39J 4 NJI4 XK39JNJI4
NI94N 4 BNER NI94NBNER
9IN3 5 ER41J 9IN3ER41J
MN83D 4 9D4S MN83D9D4S
IUN2 5 MNST3 IUN2MNST3
我的想法是将所有 ID 存储在一个列表中,然后如果它匹配,则获得一个新的随机生成的序列,但考虑到将有 300 万+ 个 id,它不起作用,因为遍历一行 3m 将花费太长时间。喜欢:
def id_generator(size, chars=string.ascii_uppercase + string.digits):
val_ls = []
val = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(size))
while val in val_ls:
val = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(size))
else:
val_ls.append(val)
return val
如何确保没有重复?
答:
1赞
Emma
1/7/2023
#1
这仍然是一种蛮力,但你可以尝试这样的事情。
from uuid import uuid4
# First generate final_id for all without caring about duplicates
df['new_id'] = df.missing.transform(lambda x: str(uuid4()).upper().replace('-', '')[:x])
df['final_id'] = df.id + df.new_id
# final_ids that are unique and already good
id_good = df.final_id.unique().tolist()
# Try re-generating final_id until we get no more duplicates
while(len(df[df.final_id.duplicated()]) > 0):
dupe_mask = df.final_id.duplicated()
# Regenerate final_id, store in temp column
df.loc[dupe_mask, 'new_id'] = df.loc[dupe_mask].missing.transform(lambda x: str(uuid4()).upper().replace('-', '')[:x])
df.loc[dupe_mask, 'temp'] = df.loc[dupe_mask].id + df.loc[dupe_mask].new_id
# If the new final_id is not duplicates with currently good final_ids, keep it.
df.loc[dupe_mask & ~df.temp.isin(id_good), 'final_id'] = df.loc[dupe_mask & ~df.temp.isin(id_good), 'temp']
id_good += df.loc[dupe_mask & ~df.temp.isin(id_good), 'final_id'].unique().tolist()
df = df.drop('temp', axis=1)
当我使用 3M 行进行测试时,它只需要执行 1 个循环,但是,您可能希望添加超时,因为理论上它可以永远运行。
评论
0赞
mjoy
1/14/2023
谢谢,这个解决方案没有花太长时间,比检查列表中的每个值都要好
评论