【问题标题】:How to create 21 random groups of 10 people 4 times, without people being in the same group如何创建 21 个 10 人的随机组 4 次,没有人在同一组中
【发布时间】:2025-11-30 08:10:01
【问题描述】:

我是 python 的新手,学习困难重重。我有一个相当乏味的任务,希望你能帮助我。

我正在为 220 人组织一个活动。全天有4个活动。活动以10人一组(22个团队)进行。目标是团队改变每一项活动。所以,我想重新安排团队组成 4 次。这是为了确保人们尽可能多地认识同事。

在 excel 中,我在 A 列中有一个包含 220 个名称的列表。我为 B 列中的每个名称 (1 -220) 分配了一个数字。我导入了模块 random 和 pandas。我的第一步是导入 excel 文件,将带有数字的 B 列变成一个列表,然后将它们打乱。

在那一步之后,我迷路了。从洗牌列表中,我想创建 22 支球队。第一次抽签后,我想再次洗牌并再次创建22支队伍,但条件是第一支队伍中没有人一起出现在第二支队伍中。这个过程总共重复了四次。

理想情况下,我想将结果导出回 excel。

希望有人可以帮助我!

再次,我正在学习,所以请分享思考过程:)。

感谢您的宝贵时间。

亲切的问候,

基础

【问题讨论】:

  • 考虑附上您的日期框架的可重现示例。并提供您的预期结果。

标签: pandas random slice shuffle


【解决方案1】:

首先,不要使用 Pandas。这是工作的错误工具。改用 NumPy。这是一个代码:

In [1]: import numpy as np

In [2]: people = np.arange(1, 221, 1)
        people
Out[2]: array([  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
                 14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,
                 27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,
                 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,
                 53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,
                 66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,
                 79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,
                 92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104,
                105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
                118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
                131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
                144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
                157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
                170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182,
                183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195,
                196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
                209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220])

In [3]: np.random.choice(people, 220, replace=False).reshape(22,10)
Out[3]: array([[ 20,  48, 164, 176, 135, 190,  67, 147, 203, 130],
               [150, 177, 171, 141, 122, 127, 202, 172,  21, 219],
               [167, 206,  84, 118, 163, 181,  34,  87, 116, 184],
               [ 33,  26,  70, 119, 129, 191, 105,  69,  86, 217],
               [ 94,  24, 146,   9,  31, 208, 179, 148,  57, 102],
               [211, 170,  65, 195, 220,  61,  88, 187,  32,   7],
               [182,  40, 144, 145, 198,  47, 193,  74,  44,  90],
               [174, 121, 216,  63,  82,  38, 201, 113,  13,  66],
               [180, 137, 214,  73,  75,  51,  80,  23,  71,  18],
               [161, 115,   3, 157,  89,  79,  29,  68, 200,   8],
               [142, 173,  98,  36, 133, 215, 138,  50,  53,   4],
               [152, 101, 139,  54,  30, 108,  49, 213, 124,  83],
               [ 76,  17,  64,  10,  56,  22, 128, 153, 158, 140],
               [131,  11,  45, 192,  92, 166,  60,  37,  12, 156],
               [104,  25,   6, 205, 212, 197,  77,  46, 199,  96],
               [ 59,  19, 112, 132, 126, 159, 151, 207,  85, 109],
               [ 42,  55, 204, 188, 185,  35,  62,  41,  27, 178],
               [ 14, 194,   2, 186, 143,  78, 134, 103, 106, 110],
               [100,  91,  99, 111,  72,  58,  15, 120, 136,  97],
               [ 39,  81, 123, 149, 165, 169, 209, 175,   1, 117],
               [189,  28,  95, 114, 162, 160, 196,   5,  93, 154],
               [210,  16, 168, 218,  43, 107, 155, 125,  52, 183]])

请注意,Out[3] 是一个 22 行 10 列的矩阵(22 组,每组 10 人)。您只需要在In [3] 中运行代码与您拥有的任务一样多。所以基本上:

In [4]: tasks = {} # Tasks is a dictionary with task number as key, and teams array as value.
        for i in np.range(1, 5, 1):
            tasks['task_' + str(i)] = np.random.choice(people, 220, replace=False).reshape(22,10)

现在,您可以将存储在tasks 中的结果带回您的 Excel 文件,然后从那里继续。如果您有任何疑虑,请告诉我。


如果您坚持使用 Pandas,并且您已经在 df 中加载了数据,那么您可以使用 Pandas 返回每个团队、每个任务的球员姓名。此代码应该足以满足您的需求:

df.set_index('player_id', inplace=True) # Which is actually pointless because
# Pandas will automatically create a 0 indexed index when you read your data in.
# So you don't even need any player_id column to begin with. If that is the case,
# change In [2] above to people = np.arange(0, 220, 1), or simply, np.arange(220)

tasks = {}
for i in np.arange(1, 5, 1):
    tasks['task_' + str(i)] = {}
    j = 1
    for team in np.random.choice(people, 220, replace=False).reshape(22,10):
      tasks[i]['team_' + str(j)] = df.loc[team].values
      j += 1

tasks在这段代码的末尾,将嵌套字典,结构如下:

tasks = {'task_1' : {'team_1'  : [list_of_players],
                     'team_2'  : [list_of_players],
                      ...
                     'team_19' : [list_of_players],
                     'team_20' : [list_of_players]},
         'task_1' : {'team_1'  : [list_of_players],
                     'team_2'  : [list_of_players],
                      ...
                     'team_19' : [list_of_players],
                     'team_20' : [list_of_players]},
         'task_1' : {'team_1'  : [list_of_players],
                     'team_2'  : [list_of_players],
                      ...
                     'team_19' : [list_of_players],
                     'team_20' : [list_of_players]},
         'task_1' : {'team_1'  : [list_of_players],
                     'team_2'  : [list_of_players],
                      ...
                     'team_19' : [list_of_players],
                     'team_20' : [list_of_players]}}

希望这会有所帮助!

【讨论】:

  • 如何安排人不见面两次?
  • 如果你真的想强制这个条件,有一个简单的数学技巧,可以在第一批团队建成后让人们四处走动。我不记得它了,但我会寻找它并相应地更新答案。
【解决方案2】:

这是一个蛮力算法 - 它依赖于随机选择,如果失败,它会再次尝试。

根本没有使用pandas,只是普通的列表和集合。

工作原理:

  • 挑选一个人加入团队
  • 如果他已经认识了某个人,请带他回去并选择另一个人
  • 否则让他加入团队,更新整个团队的met变量
  • 有时,碰巧剩下的每个人都已经遇到了团队中的某个人 - 在这种情况下,请不要打扰并提出异常

from random import choice

class Person:
    def __init__(self, name):
        self.name = name
        self.met = set()

    def __repr__(self):
        return self.name

class TooManyIteration(Exception):
    pass

GAMES = 4
TEAMS = 22
TEAMSIZE = 10

def pick_teams(s):
    s_ = s.copy()
    teams = [set() for _ in range(TEAMS)]
    for t in teams:
        c = 0
        while len(t) < TEAMSIZE:
            p = choice(tuple(s_))
            s_.remove(p)

            if all(p not in x.met for x in t):
                t.add(p)
            else:
                s_.add(p)

                c += 1
                if c > len(s):
                    # failed to pick
                    raise TooManyIteration()

    for t in teams:
        for x in t:
            x.met.update(t)

    return teams

s = set(Person(str(i)) for i in range(220))
# s = set(Person(name) for name in LIST_OF_NAMES)

games = []
while len(games) < GAMES:
    try:
        games.append(pick_teams(s))
    except TooManyIteration:
        continue
print(games)

幸运的是,你只想要四款游戏,我认为它具有指数级复杂性。

【讨论】: