You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas DataFrame转多独立Series及中学排课代码优化求助

Python自动排课实现指导

核心需求

  • 遍历学生列表及对应年级
  • 为每位学生随机分配6个时段的课程班级,每个时段1门课
  • 避免同一学生被安排同一课程的多个班级
  • 6门课中必须包含2门选修课(Elective)
  • 每个班级学生人数不超过30人

期望输出格式

格式一:按班级展示

Class 1 Section 1Class 1 Section 2
Student 1Student 3
Student 2Student 4

格式二:按学生+时段展示

Students1st Period2nd Period
Student 1Course 1 Section 1Course 3 Section 2
Student 2Course 2 Section 1Course 4 Section 1
Student 3Course 3 Section 1Course 1 Section 2

当前代码问题

现有测试代码仅针对ELA 1课程,存在以下问题:

  1. 生成的DataFrame中存储的是学生列表而非单个学生字符串,不利于后续处理
  2. 未处理时段冲突,可能出现同一学生在同一时段被安排多门课程的情况
  3. 仅单课程处理,无法满足多课程(含选修课)的分配需求

个人思路:应按时段组织数据结构(如九年级第1时段的所有课程),而非按课程类型组织。

现有测试代码

import pandas as pd

s_test = 'schedule_test.csv' # Roster of students and grade levels

df_s_test = pd.read_csv(s_test)

class_size_limit = 30

stop = 0

df_shuffle = df_s_test.sample(frac=1)

ela1 = {'ELA Section 1':[],'ELA Section 2':[],'ELA Section 3':[],'ELA Section 4':[],'ELA Section 5':[],'ELA Section 6':[]}

sections = ['Section 1','Section 2','Section 3','Section 4','Section 5','Section 6']

for s in df_shuffle.index:
    for sec in sections:
        if df_shuffle.loc[s,'Grade Level']=='9th':
            if stop==0:
                if df_shuffle.loc[s,'Student'] not in ela1[sec]:
                    if len(ela1[sec]) < class_size_limit:
                        ela1[sec]+=[df_shuffle.loc[s,'Student']]
                        stop+=1
    stop = 0

ela1 =pd.Series(ela1)

df_ela1 = pd.DataFrame({})

df_ela1 = pd.concat([df_ela1,ela1.to_frame().T],ignore_index=True)

df_ela1.to_csv('test.csv',index=False)

分步解决方案

1. 数据结构重构

创建分层数据结构,按「年级→时段→课程类型→班级」组织,同时跟踪每个班级的已选学生数:

# 定义各年级的必修/选修课程
grade_courses = {
    '9th': {
        'required': ['ELA 1', 'Algebra 1', 'Biology', 'World History'],
        'electives': ['Art 1', 'Music 1', 'PE 1', 'Computer Basics']
    },
    # 可扩展其他年级课程
    '10th': {
        'required': ['ELA 2', 'Geometry', 'Chemistry', 'US History'],
        'electives': ['Art 2', 'Music 2', 'PE 2', 'Coding 1']
    }
}

# 初始化班级容量跟踪
class_tracking = {}
for grade, course_groups in grade_courses.items():
    class_tracking[grade] = {}
    for period in range(1,7):  # 6个时段
        class_tracking[grade][period] = {}
        # 添加必修课班级
        for course in course_groups['required']:
            class_tracking[grade][period][course] = {
                'sections': [f"{course} Section {i}" for i in range(1,7)],
                'student_counts': [0]*6  # 对应每个班级的人数
            }
        # 添加选修课班级
        for course in course_groups['electives']:
            class_tracking[grade][period][course] = {
                'sections': [f"{course} Section {i}" for i in range(1,7)],
                'student_counts': [0]*6
            }

2. 学生排课逻辑实现

按年级分组学生,为每个学生分配课程,确保满足所有规则:

import random

# 读取学生数据
df_students = pd.read_csv('schedule_test.csv')
class_size_limit = 30

# 初始化学生排课结果
student_schedules = []

# 按年级分组处理
for grade, group in df_students.groupby('Grade Level'):
    courses = grade_courses[grade]
    required_courses = courses['required'].copy()
    electives = courses['electives'].copy()
    
    for _, student in group.iterrows():
        student_name = student['Student']
        schedule = {'Student': student_name}
        assigned_courses = set()
        elective_count = 0
        
        # 遍历6个时段
        for period in range(1,7):
            # 决定当前时段是必修还是选修(需满足2门选修)
            if elective_count < 2 and random.random() < 0.35:  # 随机选择选修,控制数量
                course_pool = electives
                elective_count +=1
            else:
                course_pool = [c for c in required_courses if c not in assigned_courses]
            
            # 随机选择课程
            selected_course = random.choice(course_pool)
            assigned_courses.add(selected_course)
            
            # 找到该时段该课程的未满班级
            course_info = class_tracking[grade][period][selected_course]
            available_sections = [
                idx for idx, count in enumerate(course_info['student_counts']) 
                if count < class_size_limit
            ]
            
            if not available_sections:
                # 若所有班级满员,可抛出警告或扩展班级
                print(f"Warning: All sections for {selected_course} (Period {period}) are full!")
                continue
            
            # 随机选一个未满班级
            section_idx = random.choice(available_sections)
            section_name = course_info['sections'][section_idx]
            
            # 更新班级人数
            class_tracking[grade][period][selected_course]['student_counts'][section_idx] +=1
            
            # 记录该时段课程
            schedule[f"{period}th Period"] = section_name
        
        student_schedules.append(schedule)

# 转换为DataFrame(格式二)
df_student_schedules = pd.DataFrame(student_schedules)
print(df_student_schedules.head())

3. 生成按班级展示的输出(格式一)

从排课结果中提取每个班级的学生列表:

# 初始化班级学生字典
class_students = {}

# 遍历所有学生的排课结果
for schedule in student_schedules:
    student_name = schedule['Student']
    for period_col, section in schedule.items():
        if 'Period' not in period_col:
            continue
        # 按班级分组
        if section not in class_students:
            class_students[section] = []
        class_students[section].append(student_name)

# 转换为DataFrame(格式一)
max_students = max(len(students) for students in class_students.values())
# 补全每个班级的列表长度,避免DataFrame对齐问题
for section, students in class_students.items():
    class_students[section] += ['']*(max_students - len(students))

df_class_schedules = pd.DataFrame(class_students)
print(df_class_schedules.head())

4. 保存结果

# 保存格式二的结果
df_student_schedules.to_csv('student_schedules.csv', index=False)
# 保存格式一的结果
df_class_schedules.to_csv('class_schedules.csv', index=False)

内容的提问来源于stack exchange,提问作者Gandr23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:34:58