如何在Pandas中逐行从列表列抽取不重复的随机志愿者值
Pandas 实现学校志愿者不重复随机分配
实现思路
需求本质是求学校和志愿者之间的随机完美二分匹配,要求每个学校抽到的志愿者属于自身可选列表,且所有志愿者不重复。我们优先处理可选志愿者数量少的学校,避免后续分配无可用名额,每次抽取后标记志愿者已占用,即可实现需求。
无额外依赖实现方案
import random import pandas as pd # 原始DataFrame df = pd.DataFrame({ 'poc': ["a", "b", "c", "d"], 'school': ["school1", "school2", "school3", "school4"], 'volunteers': [["sam", "mat", "ali", "mike", "guy", "john"], ["sam", "mat", "ali", "mike"], ["rose", "sam", "mike", "jorge"], ["susan", "jack", "alex", "mat", "mike"]] }) # 按可选志愿者数量从小到大排序,优先处理可选少的学校减少分配冲突 candidate_list = sorted(df['volunteers'].items(), key=lambda x: len(x[1])) used_volunteers = set() match_map = {} for idx, vol_list in candidate_list: # 过滤已被占用的志愿者 available = [v for v in vol_list if v not in used_volunteers] if not available: raise ValueError("当前数据不存在可行的不重复分配方案,请检查志愿者可选列表") # 随机抽取 selected = random.choice(available) match_map[idx] = selected used_volunteers.add(selected) # 匹配结果写入新列 df['random_match'] = df.index.map(match_map)
输出示例
| poc | school | volunteers | random_match |
|---|---|---|---|
| a | school1 | ['sam', 'mat', 'ali', 'mike', 'guy', 'john'] | john |
| b | school2 | ['sam', 'mat', 'ali', 'mike'] | sam |
| c | school3 | ['rose', 'sam', 'mike', 'jorge'] | jorge |
| d | school4 | ['susan', 'jack', 'alex', 'mat', 'mike'] | jack |
大数据量可选方案(基于networkx二分图匹配)
如果数据量较大,可使用二分图匹配库实现更稳定的分配,先安装依赖:pip install networkx
实现代码:
import networkx as nx # 构建二分图 G = nx.Graph() school_nodes = df.index.tolist() all_volunteers = list({v for lst in df['volunteers'] for v in lst}) G.add_nodes_from(school_nodes, bipartite=0) G.add_nodes_from(all_volunteers, bipartite=1) # 建立学校和可选志愿者的关联边 for idx, vol_list in df['volunteers'].items(): for v in vol_list: G.add_edge(idx, v) # 打乱边顺序实现随机匹配 edges = list(G.edges()) random.shuffle(edges) G = nx.Graph(edges) # 计算最大匹配 match_res = nx.bipartite.maximum_matching(G, top_nodes=school_nodes) df['random_match'] = df.index.map(lambda x: match_res[x])
内容的提问来源于stack exchange,提问作者AbdA
相关产品推荐
相关产品推荐

