Hello! 这里是GIS宇宙,最近在当志愿者。
最近这几天,上海疫情有所好转,学校为了给我们更大的自由度,新增特色餐券发到每个楼宇,问题在于特色餐有限,如何楼内分配是一个问题。部分楼是放回抽签,这个方法简单方便,问题就在于有些小倒霉蛋可能一次都抽不到。
因此我们采取不放回抽样,问题现有小程序没有这个功能,于是本宇宙就花了点时间写了个程序解决不放回抽样问题。
1 先说一下基本思路
- 第一次初始化,生成随机数即可,并保存抽中和没抽中的人员名单
- 第二次优先在没抽中名单里抽,如果没抽够则将不再这个名单内的人里抽
- 由此往复
什么?太绕了,听不懂?上流程图:
当剩余人数不足以满足特色餐份数的时候,这一次就是完成了所有人都吃上的任务,然后开启下次的轮回。
2 代码环节
2.1 初始化
第一次的话没有剩余人数,所以整个随机数抽人就行,然后保存一下抽中的和这次没抽中的人数,供下一次使用。
totalArr = pd.read_excel(listDir).values
selectNum = random.sample(range(0, len(totalArr)),dinnerNum)
theChosen = pd.DataFrame(totalArr[selectNum])
theLeft = pd.DataFrame(np.delete(totalArr, selectNum, axis=0))
totalArr是每层的人员名单,根据特色餐份数,生成多少个随机数,然后根据数组索引取值就行,然后保存为excel
名单格式:
id | 宿舍 | 姓名 |
---|---|---|
0 | 6xx | 张三 |
2.2 下一次计算
首先判断一下剩余人数是否小于特色餐,是的话,先把剩余人数的id获取,然后再在排除剩余人数里抽取,获取id整合到一个selectNum数组里,然后用selectNum获取人员就行。
selectNum = theOldLeft['id'].values.tolist()
leftDinnerNum = dinnerNum - len(selectNum) #计算还需要抽多少个人
#排除了少于特色餐数的人的数组
totalArr2 = np.delete(totalArr, selectNum, axis=0)
randomNum2 = random.sample(range(0, len(totalArr2)),leftDinnerNum)
for i in randomNum2:
selectNum.append(totalArr2[i][0])
theChosen = pd.DataFrame(totalArr[selectNum])
theLeft = pd.DataFrame(np.delete(totalArr, selectNum, axis=0))
如果是大于等于特色餐的话,就直接在剩余人数里面选就行。
selectNum = random.sample(range(0, len(theOldLeft)),dinnerNum)
theChosen = pd.DataFrame(theOldLeft.values[selectNum])
theLeft = pd.DataFrame(np.delete(theOldLeft.values, selectNum, axis=0))
好了今天就分享到这里,疫情期间祝大家都能身体健康、平安喜乐~