Python如何按指定概率权重从嵌套字典抽取符合分布的姓名
问题描述
假设我有如下嵌套姓名字典:
name_library = { 'us': { 'male': {'given_names': ['Alex', 'Bob', 'Charlie']}, 'female': {'given_names': ['Alice', 'Betty', 'Claire']} }, 'uk': { 'male': {'given_names': ['aaa', 'Bbb', 'cc']}, 'female': {'given_names': ['ppp', 'ddd', 'sss']} } }
需要实现按概率抽取姓名的逻辑,要求:
- 抽取结果中60%为美国(us)地区姓名,40%为英国(uk)地区姓名
- 抽取结果中男性、女性姓名占比各为50%
之前尝试参考加权概率选择字典键的思路实现,但当前场景逻辑更复杂;也曾考虑先提取字典内所有姓名再对全量姓名做分布分配,但该方案逻辑不合理,之前尝试的全量提取代码如下:
# all_possible_names = [ # name # for list_of_names in [ # self.library[area][gender][ # "given_names" # ] # for gender in self.genders # for area in self.name_areas # ] # for name in list_of_names # ] # print(all_possible_names)
实现方案
不要把所有名字拉平到一个列表再分配权重,这种方案会被不同分类下的名字数量干扰,后续调整权重也非常麻烦。用分层加权抽样的思路即可,两个维度的权重独立计算,完全不受各分类下名字数量的影响:
- 先单独按地区权重抽取选中的地区
- 再单独按性别权重抽取选中的性别
- 最后从对应地区、性别的名字列表中随机抽取一个名字即可
代码实现
用Python标准库random就能实现,不需要额外依赖:
import random # 姓名字典 name_library = { 'us': { 'male': {'given_names': ['Alex', 'Bob', 'Charlie']}, 'female': {'given_names': ['Alice', 'Betty', 'Claire']} }, 'uk': { 'male': {'given_names': ['aaa', 'Bbb', 'cc']}, 'female': {'given_names': ['ppp', 'ddd', 'sss']} } } # 权重配置,后续调整比例直接改这里就行 CONFIG = { "areas": [("us", 0.6), ("uk", 0.4)], "genders": [("male", 0.5), ("female", 0.5)] } def get_random_name() -> str: # 按权重选地区 selected_area = random.choices( population=[item[0] for item in CONFIG["areas"]], weights=[item[1] for item in CONFIG["areas"]], k=1 )[0] # 按权重选性别 selected_gender = random.choices( population=[item[0] for item in CONFIG["genders"]], weights=[item[1] for item in CONFIG["genders"]], k=1 )[0] # 从对应名字池随机选一个 return random.choice(name_library[selected_area][selected_gender]["given_names"]) # 测试:抽1000个验证占比 if __name__ == "__main__": res = [get_random_name() for _ in range(1000)] print(res[:10]) # 打印前10个结果示例
方案优势
- 权重控制精准:不会因为某类名字数量多/少打乱地区、性别的占比要求
- 维护成本低:后续新增地区、调整性别/地区权重、新增名字分类,只需要修改配置和对应字典即可,不需要改动核心抽样逻辑
- 逻辑简单:没有复杂的权重换算,分层处理比全量名字算权重的思路好理解很多
如果需要批量抽取时严格保证占比完全精准(比如抽10个必须6个us、4个uk,5男5女),可以先按权重计算好每个分类需要抽取的固定数量,再从对应名字池无放回抽样即可,常规业务场景下上述概率抽样的方案已经完全够用。
内容的提问来源于stack exchange,提问作者Ahmad Anis
相关产品推荐
相关产品推荐

