如何使用pyhton平均随机抽取年级内各个班级的学生

各位,学校要求某几天内全员常态化核酸全院学生完成,现在要求每天平均抽取每个班的学生(学生不能连号),例如学号2011951xx
班级44人,要求4天内采集完则抽取班级内几个同学(如不够除尽量平均),则按学号应该抽取11位,尽量在01~44内分开
现有表格中有数据 :学号,班级 ,姓名。总计600名学生。
要求输出excel为各个天的核酸人员。
如何用代码完成这些要求呢(工作之用,实属无奈,求解决)

假设这是你的表格

img

如果你要四次分完,就在旁边输入1,2,3,4。五次就1,2,3,4,5;以此类推。

img

选中这几个格。按住Ctrl键,并点击选中区的右下角的角点往下拖

img

拖完后的效果是这样的

img

然后从上到下选中所有的内容区域

img


然后在数据选项卡内点 排序

img


在弹出菜单里做如下选择(主要关键字根据数字这列的位置,要是你在其它列弄得这些数字就选其它列)

img

排序后,c列是1的就是第一天的学生,2的就是第二天的……

img

目前功能:
1、自定义筛选天数,比如查看某一天所有班级的所有学生
2、自定义筛选班级,比如查看某一天单个班级的所有学生
3、除了4天,可以根据自己需求定义其他的天数比如5天或者6天。

使用步骤:
1、运行以下代码,输入文件为'demo.csv',输出文件为'output.csv'
2、ctrl + t设置为超级表,然后选择最后一列为'1'即可查看第一天的,选择'2'即为第二天的,'3'为第三天的,'4'为第四天的
同时可以在第一行班级选择来筛选班级。
demo.csv和output.csv我发附件给你。



day = 4

input_file = 'demo.csv'
output_file = 'output.csv'

class_dict = {}
with open(input_file, "r") as fr:
    lines = fr.readlines()

first_line = None
for index, line in enumerate(lines):
    if index == 0:
        first_line = line
        continue
    item = line.replace('\n', '').split(',')
    _id = item[0]
    study_id = item[1]
    class_name = item[2]
    student_name = item[3]

    if class_name not in class_dict.keys():
        class_dict[class_name] = {}

    index -= 1
    number = index % 4 + 1
    class_dict[class_name][study_id] = {
        'student_name': student_name,
        'day_number': number
    }


# print("class_dict", class_dict)
with open(output_file, "w") as fw:
    fw.write(first_line.replace('\n', ',天数\n'))
    index = 0
    for class_name, class_item in class_dict.items():
        index += 1
        # 序号,学号,班级,姓名, 天数
        for study_id in class_item.keys():
            student_name = class_item[study_id]['student_name']
            day_number = class_item[study_id]['day_number']
            new_line = '{_id},{study_id},{class_name},{student_name},{day_number}\n'.format(_id=index, study_id=study_id, class_name=class_name, student_name=student_name,day_number=day_number)
            fw.write(new_line)

python的读写表格就不需要给了吧,xlwt随便查下就有教程。
主要是说一下如何平均抽取:
1、把所有人读取到一个dict;
2、总共600名,4天检完,平均每天需要抽取600/4;
3、看看总共几个班级,每班每天需要抽取600/4/班级数;
4、使用python自带random,开始挑人数,挑够了就从全集里把这个人剔除,从剩下的人里继续random

如果需要代码,那就再联系。

先写个思路:
只要提取学号和班级就可以了,因为学号是唯一的,而每个班级人数可能不一样,比如一班20人,二班30人,如果要两天做完核酸的话,一班每天做10人,二班每天做15人。
所以,

  1. 提取学号,按班级建立列表,
  2. 除以做完核酸的天数,抽取每天每个班级要做核酸的学号,
  3. 检查抽取的学号是否有连号,有则重抽,
  4. 把抽取的学号从每个班级的列表中移除,
  5. 重复步骤2到4,
  6. 倒数第二天的时候要检查剩下的学号有没有连号,有的话两天都要重抽,
  7. 把每天抽取的学号按天输出到excel。

题主确认一下是这个思路不?

random 获取随机数,然后再把需要的数据在python内进行读取拼接,输出,完事。

每个学生一个编号,例如46个学生,就是1-46个编号,每个编号对应一个学生,取random取编号(平均几次,一个班就取几次)

不太懂你的意思,是随机产生学号吗?


import random
day = 3
num = []
for i in range(int(44 / day)):
    num.append(random.randint(1,44))

num = sorted(num)

for j in num:
    print("2011951{}".format(j))

就分层抽就可以了。你发我excel ,我测试一下

这个要看你是每天每个班采集一部分人,再从这一部分人中抽取几位,4天共抽11人
还是4天采集完后统一每个班抽取11人。

import math
import random
# pip install openpyxl
import openpyxl

# Excel表结构
#    A列         B列        C列      D列 
#   班级       学号          姓名     第几天
#    A    201195101    name_101    3
#    A    201195102    name_102    3
#    A    201195103    name_103    1
#    A    201195104    name_104    1
#    A    201195105    name_105    4
#    A    201195106    name_106    4
#    A    201195107    name_107    2

# 未能通过实现让每天检测的人员实现不连号的情况,这应只是概率问题,相信一直循环验证是可以实现的
# 本机10000次以内未能出现不连号的情况。

class Student(object):
    """docstring for Student"""
    def __init__(self, exl_name):
        super(Student, self).__init__()
        self.exl_name = exl_name
        self.wb = self.get_wb()
        self.sheet = self.wb.active
        self.stu_info = self.get_stu_info()

    def get_wb(self):
        # 加载Excel表
        wb = openpyxl.load_workbook(filename=self.exl_name)
        return wb

    def get_stu_info(self):
        # 获取数据
        stu_info = dict()
        for row in self.sheet.iter_rows(min_row=2,max_col=3):
            class_name = row[0].value
            stu_number = row[1].value
            stu_name = row[2].value
            if class_name not in stu_info:
                stu_info[class_name] = list()
            dic = {"name":stu_name,"number":stu_number}
            stu_info[class_name].append(dic)
        # print(stu_info)
        return stu_info

    def avg_count(self,class_name,days):
        # 获得每班平均每天人数
        stus = self.stu_info[class_name]        
        avg_count = math.ceil(len(stus)/days)
        return avg_count

    def avg_stu(self,class_name,days):
        # 按每天每班人数 抽取学号  如果不连号是否能够实现?既然是随机抽取那么连号和不连号的意义是什么?
        choice_data = dict()
        stus = self.stu_info[class_name]
        stu_numbers = [stu["number"] for stu in stus]
        avg_count = self.avg_count(class_name,days)
        for day in range(1,days+1):
            choice_data[day] = list()            
            if len(stu_numbers)>=avg_count:
                for count in range(1,avg_count+1):        
                    stu_num = random.choice(stu_numbers)
                    choice_data[day].append(stu_num)
                    stu_numbers.remove(stu_num)
            else:
                choice_data[day].extend(stu_numbers)
        # print(choice_data)
        return choice_data        
        
    def check_nums(self,everyday_stus,days):    
        # 检查当天检测学号是否连号
        # 既然是随机抽取 那么连号和不连号就是概率问题了  没有测出能出现不连号的情况
       # 判断连号不连号的情况 本机测试一直没有通过
        for day in range(1,days+1):
            stus = everyday_stus[day]
            stus.sort()
            # print(day,stus)
            for index in range(1,len(stus)):                
                if stus[index]-stus[index-1] == 1:
                    print(day,stus[index],stus[index-1])
                    return False        
        return True


    def run(self):        
        # 获取班级名称
        class_names = list(self.stu_info.keys())
        # 所需总天数
        days = 4
        # days = int(input("输入天数:"))
        everyday_stus = dict()
        # 循环获取数据校验是否存在连号
        while 1:            
            for class_name in class_names:
                choice_data = self.avg_stu(class_name,days)
                for day in range(1,days+1):
                    if day not in everyday_stus:
                        everyday_stus[day] = list()
                    everyday_stus[day].extend(choice_data[day])
            print("over")
            self.write_exl(everyday_stus)
            return
            # 如果需要校验学号是否连号 去掉return开始校验
            if self.check_nums(everyday_stus,days) is True:
                print("over")
                self.write_exl(everyday_stus)
                return 
        # self.check_nums(everyday_stus)
    def write_exl(self,everyday_stus):
        # 写入Excel
        for key,val in everyday_stus.items():
            for number in val:
                for row in self.sheet.iter_rows(min_row=2,min_col=2,max_col=4):
                    stu_num = row[0].value
                    if number == stu_num:
                        row[-1].value=key
        # 保存
        self.wb.save("student_over.xlsx")


if __name__=="__main__":
    stu = Student(exl_name="student.xlsx")
    stu.run()

如果真实纯工作需要,还是用表格处理吧,楼上有给出表格处理的方案,简单效率

把现有表格给我,可以调试实现你的功能。

贴主不适合编程,连python也能拼写错误

具体操作链接