Python中如何实现元组列表带权重无放回的随机子集抽取?
加权无放回抽样实现方案
你需要的带权重无放回抽样可以通过以下三种方法实现,全部支持元组列表作为输入:
方案1:Python 3.9+ 原生实现(最优方案)
Python 3.9及以上版本的random.sample接口已经原生支持weights加权参数,无需额外依赖,也不限制输入元素类型:
import random # 示例待选元组列表,可直接替换为你的实际数据 item_list = [("red", 10), ("orange", 10), ("blue", 10), ("yellow", 10), ("green", 50)] # 提取对应权重,也可以直接写独立的权重列表 weights = [i[1] for i in item_list] # 无放回抽取3个元素,自动遵循权重概率 selected = random.sample(item_list, k=3, weights=weights) print(selected)
方案2:低版本Python兼容实现
如果使用3.9以下版本的Python,可以手动实现加权抽样逻辑,每次抽取一个元素后从待选池移除该元素及其权重,直到抽够目标数量:
import random from itertools import accumulate import bisect def weighted_sample(population, weights, k): # 复制原数据避免修改原列表 pop_copy = population.copy() weight_copy = weights.copy() res = [] for _ in range(k): cum_weights = list(accumulate(weight_copy)) total = cum_weights[-1] # 按权重随机选中对应索引 idx = bisect.bisect_left(cum_weights, random.uniform(0, total)) res.append(pop_copy.pop(idx)) weight_copy.pop(idx) return res # 调用示例 item_list = [("red", 10), ("orange", 10), ("blue", 10), ("yellow", 10), ("green", 50)] weights = [i[1] for i in item_list] print(weighted_sample(item_list, weights, 3))
方案3:Numpy实现(适配已有numpy依赖的项目)
你提到的numpy.random.choice无法直接传入元组列表的问题可以通过抽索引的方式解决:
import numpy as np item_list = [("red", 10), ("orange", 10), ("blue", 10), ("yellow", 10), ("green", 50)] # 权重需要归一化到和为1 weights = np.array([i[1] for i in item_list], dtype=np.float64) weights /= weights.sum() # 先对索引做无放回加权抽样 selected_idx = np.random.choice(len(item_list), size=3, replace=False, p=weights) # 按索引取对应元组 selected = [item_list[i] for i in selected_idx] print(selected)
内容的提问来源于stack exchange,提问作者Nikki
相关产品推荐
相关产品推荐

