最近我遇到了一个有趣的问题,我的导师想要提前将下一届的学生分配给各位教师。这听起来似乎没什么大不了的,但实际上,这可是个挺头疼的事情。
幻想一下,你作为一名导师,要负责领导一群研究生。你希望这些学生和你的研究方向相符,又能发挥他们的潜力。但问题是,假如分配不公正,可能会导致资源浪费,甚至影响到学生的学习和研究。
所以,我决议动手写一个随机分配的脚原本处理这个问题。这样一来,分配就不会受到个人喜爱或偏见的影响,而是彻底随机的,公正并且透明。
在这篇博客里,我将和大家共享我的思路和完成进程。希望这关于遇到类似问题的人有所启示和协助!
主要技术栈
- Dash结构:Dash是根据Python的Web应用结构,用于构建交互式Web应用程序。
- Pandas库:Pandas是Python中用于数据处理和剖析的强壮库。
分配进程
首先,让我们简要地了解一下这个脚本的作业原理。我编写了一个根据Dash的Python应用程序,其间包含了两个重要功用:手动分配和随机分配。
- 手动分配: 用户可以手动输入学生的学号和导师的名字,然后单击按钮将学生分配给指定的导师。这关于一些特殊情况下的指定分配非常有用。
- 随机分配: 用户可以上传包含导师和学生信息的CSV或Excel文件,然后单击按钮履行随机分配。在这种形式下,脚本将根据每个导师可以分配的学生数量随机将学生分配给导师。
大致逻辑
现在,让我们深入了解一下脚本的逻辑。我使用了Dash来构建用户界面,这是一个根据Python的Web应用程序结构。经过Dash,我可以轻松地创立交互式组件,并将它们与Python函数进行衔接。
在数据处理方面,我使用了Pandas库来处理上传的CSV或Excel文件。Pandas供给了丰厚的数据操作功用,使我可以轻松地读取、处理和操作数据。
随机分配的部分则利用了Python的随机模块。我首先将导师和他们可以分配的学生数量存储在一个字典中,然后根据每个导师的指定数量随机选择学生,并将它们分配给对应的导师。
最终,我使用了Dash的回调函数来完成交互逻辑。每当用户履行操作时,回调函数将被触发,并相应地更新界面或履行其他操作。
代码
当我规划这个随机分配脚本时,我将功用分为几个部分。让我逐段解释每个部分的代码:
1. 导入必要的库和模块
import random
import time
import dash
from dash import dcc, html
from dash.dependencies import Input, Output, State
import pandas as pd
import base64
import io
在这一部分,我导入了所需的Python库和模块。这些库包括Dash用于构建Web应用程序,Pandas用于数据处理,以及其他一些用于处理文件上传和编码的模块。
2. 设置Dash应用程序
app = dash.Dash(__name__)
这行代码创立了一个Dash应用程序实例。我将其命名为app
,并指定__name__
作为应用程序的称号。
3. 规划应用程序的布局
app.layout = html.Div([
# 上传导师信息文件的组件
dcc.Upload(
id='upload-data1',
children=html.Div([
'上传CSV或Excel文件(教师)'
]),
style={...},
accept='.csv, .xlsx'
),
# 上传学生信息文件的组件
dcc.Upload(
id='upload-data2',
children=html.Div([
'上传一个CSV或Excel文件(学生)'
]),
style={...},
accept='.csv, .xlsx'
),
# 输入学生学号和教师名字的组件
html.Div([
html.Label('学生学号:'),
dcc.Input(id='student-id', type='text', value=''),
html.Label('教师名字:'),
dcc.Input(id='teacher-name', type='text', value=''),
html.Button('分配教师', id='assign-button', n_clicks=0),
html.Div(id='assign-output')
]),
# 开端随机分配按钮和设置每个教师分配的学生数量
html.Div([
html.Label('每个教师分配的学生数量:'),
html.Button('开端随机分配', id='random-button', n_clicks=0),
html.Div(id='random-output')
])
])
这段代码定义了Dash应用程序的布局。我创立了几个上传文件和输入框组件,以便用户上传导师和学生的信息文件,并手动分配学生给指定的导师。一起,我还增加了一个按钮,用于开端随机分配学生。
4. 解析上传的文件
# 上传函数
def parse_contents(contents, filename,target):
global teacher_df, student_df,teacher_df_all,student_df_all
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename:
# 读取上传的CSV文件,一起指定学号列的数据类型为字符串
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')), dtype={'学号': str})
elif 'xls' in filename or 'xlsx' in filename:
# 读取上传的Excel文件,一起指定学号列的数据类型为字符串
df = pd.read_excel(io.BytesIO(decoded), dtype={'学号': str})
except Exception as e:
print(e)
return html.Div([
'产生错误,无法读取文件'
])
# 根据目标标识存储到相应的全局变量中
if target == 'teacher':
teacher_df = df
teacher_df_all = df
elif target == 'student':
student_df = df
student_df_all = df
return df.to_dict('records')
这个函数用于解析上传的CSV或Excel文件,并将其转换为Pandas DataFrame格式。我使用了Dash的上传组件来处理文件上传操作,并在这个函数中完成了具体的解析逻辑。
5. 手动分配学生给指定导师
@app.callback(Output('assign-output', 'children'),
Input('assign-button', 'n_clicks'),
State('student-id', 'value'),
State('teacher-name', 'value'))
def assign_student_to_teacher(n_clicks, student_id, teacher_name):
...
这个回调函数用于处理手动分配学生给指定导师的操作。当用户点击分配按钮时,该函数将被触发,并根据输入的学生学号和导师名字履行分配操作。
6. 更新上传文件后的界面
# 烘托第一个表格
@app.callback(Output('output-data-upload1', 'children'),
Input('upload-data1', 'contents'),
Input('upload-data1', 'filename'),
Input('assign-output', 'children'))
def update_output1(contents, filename, assign_output):
global teacher_df
if contents is not None or teacher_df is not None:
# 判别哪个输入触发了回调
ctx = dash.callback_context
triggered_input = ctx.triggered[0]['prop_id'].split('.')[0]
if triggered_input == 'assign-output':
# 假如是 assign-output 触发的回调,履行相应的操作
# 返回更新后的内容
print("触发分配更新烘托回调")
else:
children = parse_contents(contents, filename, "teacher")
return html.Div([ # 返回一个 Div 包裹,确保在回调中可以更新内容
html.Table([
html.Thead(
[html.Tr([html.Th(col) for col in teacher_df.columns])]
),
html.Tbody([
html.Tr([
html.Td(val) for val in row
]) for row in teacher_df.values
])
]),
assign_output # 显现分配输出成果
])
else:
return assign_output # 显现分配输出成果
这个回调函数用于更新上传文件后的界面。当用户上传了导师信息文件时,该函数将被触发,并更新界面以显现上传的文件内容。
7. 履行随机分配学生操作
# 履行随机分配学生操作
# 在回调函数中增加保存到CSV的逻辑
@app.callback(
Output('random-output', 'children'),
Input('random-button', 'n_clicks')
)
def random_assign_students_callback(n_clicks):
global teacher_df, student_df, teacher_students, teacher_df_all, student_df_all
if n_clicks > 0 and teacher_df is not None and student_df is not None:
# 以教师名单中的人数列为根据,将教师及其对应的人数转换为字典
teacher_dict = dict(zip(teacher_df['教师'], teacher_df['人数']))
# 调用随机分配学生函数,传入教师人数字典和学生列表
random_results = random_assign_students(teacher_dict, student_df)
# 将已指定的教师和学生信息加入到随机分配成果中
for teacher, students in teacher_students_zhiding.items():
if teacher in random_results:
random_results[teacher].extend(students)
else:
random_results[teacher] = students
# 将随机分配成果保存为CSV文件
save_random_results_to_csv(random_results)
# 显现分配成果
output = html.Div([
html.H3('随机分配成果:'),
])
# 遍历每个教师的学生列表
for teacher, students in random_results.items():
# 创立一个包含教师名和学生数量的表格
teacher_table = html.Table([
html.Thead(html.Tr([html.Th('教师'), html.Th('学生数量')])),
html.Tbody([
html.Tr([
html.Td(teacher),
html.Td(len(students))
])
])
])
# 创立一个包含学生学号、名字、班级和电话的表格
student_table = html.Table([
html.Thead(html.Tr([html.Th('学生学号'), html.Th('学生名字'), html.Th('班级'), html.Th('电话')])),
html.Tbody([
html.Tr([
html.Td(student[0]), # 学生学号
html.Td(student[1]), # 学生名字
html.Td(student_df_all.loc[student_df_all['学号'] == student[0], '班级'].values[0]), # 班级
html.Td(student_df_all.loc[student_df_all['学号'] == student[0], '电话'].values[0]) # 电话
]) for student in students
])
])
# 将教师表格和学生表格放入一个 Div 中
output.children.append(html.Div([teacher_table, student_table]))
elif n_clicks > 0:
output = html.Div('请先上传教师和学生信息文件')
else:
output = html.Div()
return output
这个回调函数用于履行随机分配学生的操作。当用户点击随机分配按钮时,该函数将被触发,并随机将学生分配给导师。
8. 保存随机分配成果到CSV文件
def save_random_results_to_csv(random_results):
# 创立一个空的DataFrame来存储成果
result_df = pd.DataFrame(columns=['教师', '学生学号', '学生名字', '班级', '电话'])
# 遍历每个教师的学生列表,将成果增加到DataFrame中
for teacher, students in random_results.items():
temp_df = pd.DataFrame(students, columns=['学生学号', '学生名字'])
temp_df['教师'] = teacher
temp_df['班级'] = temp_df['学生学号'].apply(lambda x: student_df_all.loc[student_df_all['学号'] == x, '班级'].values[0])
temp_df['电话'] = temp_df['学生学号'].apply(lambda x: student_df_all.loc[student_df_all['学号'] == x, '电话'].values[0])
result_df = pd.concat([result_df, temp_df], ignore_index=True)
# 保存DataFrame为CSV文件
result_df.to_csv('随机分配成果.csv', index=False)
这个函数用于将随机分配的成果保存到CSV文件中。我将每个导师分配的学生信息保存到一个CSV文件中,以便进一步剖析或导入到其他系统中。
结束语
这个脚本被我上传到了Gitee,有jy感兴趣的话可以下载下来玩玩,假如各位感兴趣的大佬给个star。
导师随机分配: 这个脚本是一个根据Dash结构的Web应用程序,用于教师和学生信息的办理和随机、指定分配。 (gitee.com)