如何编写自动分班的脚本

wen 实用脚本 1

本文目录导读:

如何编写自动分班的脚本

  1. 基础版本 - 随机分班
  2. 均衡分班版本
  3. 指标优化分班版本
  4. 带权重约束的分班
  5. 使用示例
  6. 分班效果评估

我来提供一个完整的自动分班脚本方案,包含多种分班策略和详细的代码示例。

基础版本 - 随机分班

import pandas as pd
import numpy as np
from datetime import datetime
class AutoClassAssigner:
    def __init__(self, student_file, class_count=5):
        """
        初始化分班器
        :param student_file: 学生数据文件路径
        :param class_count: 班级数量
        """
        self.students_df = pd.read_excel(student_file)
        self.class_count = class_count
        self.classes = {}
    def random_assign(self, seed=None):
        """随机分班"""
        if seed:
            np.random.seed(seed)
        # 打乱顺序
        shuffled = self.students_df.sample(frac=1).reset_index(drop=True)
        # 平均分配到各班
        for i in range(self.class_count):
            start_idx = i * len(shuffled) // self.class_count
            end_idx = (i + 1) * len(shuffled) // self.class_count
            self.classes[f'班级{i+1}'] = shuffled.iloc[start_idx:end_idx]
        return self.classes
    def export_result(self, filename='分班结果.xlsx'):
        """导出分班结果"""
        with pd.ExcelWriter(filename) as writer:
            # 汇总表
            summary_data = []
            for class_name, class_df in self.classes.items():
                summary_data.append({
                    '班级': class_name,
                    '人数': len(class_df)
                })
            pd.DataFrame(summary_data).to_excel(writer, sheet_name='班级人数汇总', index=False)
            # 每个班级单独一页
            for class_name, class_df in self.classes.items():
                class_df.to_excel(writer, sheet_name=class_name, index=False)

均衡分班版本

class BalancedClassAssigner(AutoClassAssigner):
    def __init__(self, student_file, class_count=5, balance_columns=['性别', '成绩']):
        super().__init__(student_file, class_count)
        self.balance_columns = balance_columns
    def balanced_assign(self):
        """均衡分班 - 确保各班在特定属性上相近"""
        df = self.students_df.copy()
        # 初始化各班列表
        class_members = {f'班级{i+1}': [] for i in range(self.class_count)}
        # 按学科成绩排序(蛇形分配)
        if '成绩' in self.balance_columns:
            df = df.sort_values('成绩', ascending=False)
        # 蛇形分配算法
        direction = 1  # 1表示正序,-1表示倒序
        current_class = 0
        for idx, student in df.iterrows():
            # 选择班级
            class_name = f'班级{current_class + 1}'
            class_members[class_name].append(student)
            # 切换班级
            current_class += direction
            # 到达边界时反向
            if current_class >= self.class_count:
                current_class = self.class_count - 1
                direction = -1
            elif current_class < 0:
                current_class = 0
                direction = 1
        # 转换为DataFrame
        for class_name, members in class_members.items():
            self.classes[class_name] = pd.DataFrame(members)
        return self.classes
    def check_balance(self):
        """检查各班均衡性"""
        print("=" * 50)
        print("分班均衡性检查")
        print("=" * 50)
        for col in self.balance_columns:
            if col not in ['性别', '班级平均成绩']:
                print(f"\n{col}分布情况:")
                for class_name, class_df in self.classes.items():
                    if col == '性别':
                        male_count = len(class_df[class_df[col] == '男'])
                        female_count = len(class_df[class_df[col] == '女'])
                        print(f"{class_name}: 男 {male_count}人, 女 {female_count}人")
                    elif col == '成绩':
                        avg = class_df[col].mean()
                        print(f"{class_name}: 平均成绩 {avg:.1f}分")

指标优化分班版本

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
class OptimizedClassAssigner(AutoClassAssigner):
    def __init__(self, student_file, class_count=5, weights=None):
        """
        :param weights: 各指标的权重字典,如 {'成绩': 0.6, '性别': 0.2, '地区': 0.2}
        """
        super().__init__(student_file, class_count)
        self.weights = weights or {'成绩': 0.5, '性别': 0.2, '地区': 0.3}
    def optimize_assign(self):
        """基于K-means的优化分班"""
        df = self.students_df.copy()
        # 特征编码
        features = []
        # 数值特征标准化
        numeric_cols = [col for col in ['成绩', '年龄'] if col in df.columns]
        if numeric_cols:
            for col in numeric_cols:
                df[f'{col}_norm'] = (df[col] - df[col].mean()) / df[col].std()
                features.append(f'{col}_norm')
        # 分类特征one-hot编码
        if '性别' in df.columns:
            df['性别男'] = (df['性别'] == '男').astype(int)
            features.append('性别男')
        # 区域编码
        if '地区' in df.columns:
            df = pd.get_dummies(df, columns=['地区'], prefix='地区')
            features += [col for col in df.columns if col.startswith('地区_')]
        # K-means聚类
        X = df[features].values
        scaler = StandardScaler()
        X_scaled = scaler.fit_transform(X)
        # 每个样本的类别数等于班级数
        kmeans = KMeans(n_clusters=self.class_count, random_state=42)
        df['分配组'] = kmeans.fit_predict(X_scaled)
        # 从各组中轮流抽取学生到各班
        class_members = {f'班级{i+1}': [] for i in range(self.class_count)}
        for group in range(self.class_count):
            group_students = df[df['分配组'] == group]
            for idx, (i, student) in enumerate(group_students.iterrows()):
                # 分配到不同班级
                class_idx = (idx + group) % self.class_count
                class_name = f'班级{class_idx + 1}'
                class_members[class_name].append(student)
        # 整理结果
        for class_name, members in class_members.items():
            self.classes[class_name] = pd.DataFrame(members).drop(columns=['分配组'])
        return self.classes

带权重约束的分班

class WeightedClassAssigner(AutoClassAssigner):
    def __init__(self, student_file, class_count=5, constraints=None):
        super().__init__(student_file, class_count)
        # 约束条件示例
        self.constraints = constraints or {
            '性别平衡': True,
            '成绩均衡': True,
            '地区分散': True,
            '男生班级': None  # 可以指定哪些班级全男生
        }
    def assign_with_constraints(self):
        """带约束条件的分班"""
        df = self.students_df.copy()
        # 初始化
        class_members = {f'班级{i+1}': [] for i in range(self.class_count)}
        used_indices = set()
        # 处理特殊班级(如男生班)
        if self.constraints.get('男生班级'):
            male_students = df[df['性别'] == '男']
            special_class = self.constraints['男生班级']
            male_count = len(male_students) // self.class_count
            class_members[special_class] = list(male_students.head(male_count).index)
            used_indices.update(male_students.head(male_count).index)
        # 蛇形分配剩余学生
        remaining = df.drop(index=used_indices)
        remaining = remaining.sort_values('成绩', ascending=False)
        # 按成绩分组,每组从不同成绩段抽取
        group_size = len(remaining) // self.class_count
        for class_idx in range(self.class_count):
            current_members = []
            for group in range(self.class_count):
                start = group * group_size
                end = (group + 1) * group_size
                if start < len(remaining):
                    pool = remaining.iloc[start:end]
                    if len(pool) > 0:
                        # 从该段随机选一个学生
                        chosen_idx = np.random.choice(pool.index)
                        current_members.append(chosen_idx)
                        used_indices.add(chosen_idx)
                        remaining = remaining.drop(index=chosen_idx)
            class_members[f'班级{class_idx + 1}'].extend(current_members)
        # 处理剩余学生
        for i, idx in enumerate(remaining.index):
            class_name = f'班级{i % self.class_count + 1}'
            class_members[class_name].append(idx)
        # 转换格式
        for class_name, indices in class_members.items():
            self.classes[class_name] = df.loc[indices]
        return self.classes

使用示例

def main():
    # 示例数据生成
    import random
    # 生成100个学生样本数据
    students = []
    names = [f'学生{i+1}' for i in range(100)]
    for i, name in enumerate(names):
        students.append({
            '姓名': name,
            '学号': f'2024{i+1:04d}',
            '性别': np.random.choice(['男', '女'], p=[0.5, 0.5]),
            '成绩': np.random.normal(75, 15),  # 正态分布的成绩
            '地区': np.random.choice(['A区', 'B区', 'C区', 'D区']),
            '年龄': np.random.choice([15, 16, 17])
        })
    df = pd.DataFrame(students)
    df.to_excel('students.xlsx', index=False)
    # 使用分班器
    print("=" * 60)
    print("自动分班系统")
    print("=" * 60)
    # 1. 随机分班
    print("\n1. 随机分班")
    assigner = AutoClassAssigner('students.xlsx', class_count=5)
    result = assigner.random_assign()
    assigner.export_result('random_assign_result.xlsx')
    # 2. 均衡分班
    print("\n2. 均衡分班")
    balanced_assigner = BalancedClassAssigner('students.xlsx', class_count=5)
    balanced_assigner.balanced_assign()
    balanced_assigner.check_balance()
    balanced_assigner.export_result('balanced_assign_result.xlsx')
    # 3. 优化分班
    print("\n3. 优化分班")
    optimizer = OptimizedClassAssigner('students.xlsx', class_count=5)
    optimizer.optimize_assign()
    optimizer.export_result('optimized_assign_result.xlsx')
    # 4. 带约束分班
    print("\n4. 带约束分班")
    constrained = WeightedClassAssigner('students.xlsx', class_count=5)
    constrained.assign_with_constraints()
    constrained.export_result('constrained_assign_result.xlsx')
    print("\n分班完成!结果已保存到Excel文件。")
if __name__ == "__main__":
    main()

分班效果评估

class ClassEvaluator:
    @staticmethod
    def evaluate(class_assigner):
        """评估分班效果"""
        if not class_assigner.classes:
            print("没有分班结果!")
            return
        print("\n" + "=" * 60)
        print("分班效果评估")
        print("=" * 60)
        # 1. 人数统计
        print("\n【人数统计】")
        for class_name, class_df in class_assigner.classes.items():
            total = len(class_df)
            male = len(class_df[class_df['性别'] == '男']) if '性别' in class_df.columns else 0
            female = total - male
            print(f"{class_name}: 共{total}人 (男{male}人, 女{female}人)")
        # 2. 成绩统计
        if '成绩' in class_assigner.students_df.columns:
            print("\n【成绩分析】")
            scores = []
            for class_name, class_df in class_assigner.classes.items():
                avg = class_df['成绩'].mean()
                std = class_df['成绩'].std()
                max_score = class_df['成绩'].max()
                min_score = class_df['成绩'].min()
                scores.append(avg)
                print(f"{class_name}: 平均{avg:.1f}分, 最高{max_score:.1f}分, 最低{min_score:.1f}分")
            # 班级间差异
            if len(scores) > 1:
                diff = max(scores) - min(scores)
                print(f"\n班级平均分差距: {diff:.1f}分")
                if diff < 5:
                    print("均衡性: 很好!")
                elif diff < 10:
                    print("均衡性: 一般")
                else:
                    print("均衡性: 需要改进")

这个脚本提供了完整的分班解决方案,可以根据实际需求选择不同的分班策略,并支持自定义约束条件。

抱歉,评论功能暂时关闭!