本文目录导读:

我来提供一个完整的自动分班脚本方案,包含多种分班策略和详细的代码示例。
基础版本 - 随机分班
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("均衡性: 需要改进")
这个脚本提供了完整的分班解决方案,可以根据实际需求选择不同的分班策略,并支持自定义约束条件。