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

基于性别与班级属性的学生最大多样性分组方案咨询

最大化学生分组多样性的实现方案

现有20名学生,需划分为6个3人组和1个2人组,核心目标是最大化每组内性别与班级的多样性——即尽量减少组内同性别或同班级学生的占比,促进不同背景学生融合。此前尝试用KMeans聚类仅完成了属性数值化,未解决分组分配问题,以下是可行的实现方案。

一、先明确学生属性分布

首先统计原始数据中各属性组合的学生数量,这是分组的基础:

import pandas as pd

data = [{'name': 'Katina', 'gender': 'f', 'class': 'a'}, {'name': 'Mary', 'gender': 'f', 'class': 'a'}, {'name': 'Manuel', 'gender': 'm', 'class': 'b'}, {'name': 'Timothy', 'gender': 'm', 'class': 'b'}, {'name': 'Eunice', 'gender': 'f', 'class': 'a'}, {'name': 'Gary', 'gender': 'm', 'class': 'a'}, {'name': 'Michael', 'gender': 'm', 'class': 'a'}, {'name': 'Melanie', 'gender': 'f', 'class': 'b'}, {'name': 'Edward', 'gender': 'm', 'class': 'a'}, {'name': 'Jessie', 'gender': 'm', 'class': 'b'}, {'name': 'Elizabeth', 'gender': 'f', 'class': 'a'}, {'name': 'Jared', 'gender': 'm', 'class': 'a'}, {'name': 'Jose', 'gender': 'm', 'class': 'b'}, {'name': 'Amado', 'gender': 'm', 'class': 'b'}, {'name': 'Matthew', 'gender': 'm', 'class': 'a'}, {'name': 'Charlie', 'gender': 'm', 'class': 'a'}, {'name': 'Willie', 'gender': 'm', 'class': 'b'}, {'name': 'Mary', 'gender': 'f', 'class': 'a'}, {'name': 'Susan', 'gender': 'f', 'class': 'b'}, {'name': 'Michael', 'gender': 'm', 'class': 'b'}]
df = pd.DataFrame(data)

# 统计各属性组合的人数
group_counts = df.groupby(['gender', 'class']).size().reset_index(name='count')
print(group_counts)

运行后得到各群体人数:

genderclasscount
fa6
fb3
ma7
mb4

二、为什么KMeans不适用

KMeans的核心逻辑是将相似样本聚集到同一簇,但我们的需求是异质分组——让每组包含尽可能多不同属性的学生,两者目标完全相反,因此KMeans无法直接解决这个问题。

三、可行方案:贪心算法(简单易实现)

贪心算法的思路是:每次组建组时,优先从当前剩余人数最多的属性组合中选取学生,再搭配其他属性组合的学生,尽量让每组覆盖最多的不同类别,避免同属性扎堆。

实现代码

import random

# 按属性组合拆分学生列表
fa_students = df[(df['gender'] == 'f') & (df['class'] == 'a')]['name'].tolist()
fb_students = df[(df['gender'] == 'f') & (df['class'] == 'b')]['name'].tolist()
ma_students = df[(df['gender'] == 'm') & (df['class'] == 'a')]['name'].tolist()
mb_students = df[(df['gender'] == 'm') & (df['class'] == 'b')]['name'].tolist()

# 打乱列表,增加随机性
random.shuffle(fa_students)
random.shuffle(fb_students)
random.shuffle(ma_students)
random.shuffle(mb_students)

groups = []

# 先创建6个3人组
for _ in range(6):
    group = []
    # 按剩余人数降序排序候选群体
    candidates = [('fa', fa_students), ('fb', fb_students), ('ma', ma_students), ('mb', mb_students)]
    candidates.sort(key=lambda x: len(x[1]), reverse=True)
    
    # 优先选不同属性组合的学生
    for i in range(3):
        if len(candidates[i][1]) > 0:
            group.append(candidates[i][1].pop())
        else:
            # 若当前类别为空,从下一个非空类别补选
            for j in range(i+1, 4):
                if len(candidates[j][1]) > 0:
                    group.append(candidates[j][1].pop())
                    break
    groups.append(group)

# 创建最后1个2人组
last_group = []
candidates = [('fa', fa_students), ('fb', fb_students), ('ma', ma_students), ('mb', mb_students)]
candidates.sort(key=lambda x: len(x[1]), reverse=True)
# 优先选不同属性组合的学生
for i in range(2):
    if len(candidates[i][1]) > 0:
        last_group.append(candidates[i][1].pop())
groups.append(last_group)

# 输出分组结果
for idx, group in enumerate(groups, 1):
    print(f"组{idx}: {group}")

效果说明

该算法会尽量让每个3人组包含2-3种不同的属性组合,2人组包含2种不同组合,最大化组内多样性。由于加入了随机打乱,每次运行结果会有差异,但都能满足多样性要求。

四、进阶方案:整数规划(最优解)

如果需要严格的最优解(即所有组的多样性总和最大),可以用整数规划工具(如PuLP),定义目标函数为最小化所有组内同性别或同班级的学生对数,约束条件包括:

  • 每个学生仅属于一个组
  • 6个组有3名学生,1个组有2名学生

核心思路示例

from pulp import LpProblem, LpMinimize, LpVariable, lpSum

# 定义基础数据
students = df['name'].tolist()
num_students = len(students)
groups = [f'group_{i}' for i in range(7)]
group_sizes = [3]*6 + [2]

# 初始化规划问题
prob = LpProblem("MaximizeGroupDiversity", LpMinimize)

# 定义变量:x[i][g] = 1表示学生i属于组g
x = LpVariable.dicts("x", [(s, g) for s in students for g in groups], cat='Binary')

# 目标函数:最小化组内同性别+同班级的学生对数
cost = 0
for g in groups:
    # 计算同性别对数
    for i in range(num_students):
        for j in range(i+1, num_students):
            if df.loc[df['name'] == students[i], 'gender'].values[0] == df.loc[df['name'] == students[j], 'gender'].values[0]:
                cost += x[(students[i], g)] * x[(students[j], g)]
    # 计算同班级对数
    for i in range(num_students):
        for j in range(i+1, num_students):
            if df.loc[df['name'] == students[i], 'class'].values[0] == df.loc[df['name'] == students[j], 'class'].values[0]:
                cost += x[(students[i], g)] * x[(students[j], g)]
prob += cost

# 约束1:每个学生仅在一个组
for s in students:
    prob += lpSum([x[(s, g)] for g in groups]) == 1

# 约束2:每组人数符合要求
for g_idx, g in enumerate(groups):
    prob += lpSum([x[(s, g)] for s in students]) == group_sizes[g_idx]

# 求解
prob.solve()

# 输出分组结果
group_assignments = {g: [] for g in groups}
for s in students:
    for g in groups:
        if x[(s, g)].value() == 1:
            group_assignments[g].append(s)

for g, members in group_assignments.items():
    print(f"{g}: {members}")

说明

整数规划能给出理论上的最优解,但实现复杂度更高,适合对分组结果要求严格的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 10:35:37