python - 将参与者随机重新分配到组中,以便最初来自同一组的参与者最终不会出现在同一组中

标签 python pandas random data-science experimental-design

我基本上正在尝试进行这种蒙特卡洛分析,其中我将实验中的参与者随机重新分配到新组,然后重新分析给定随机新组的数据。这就是我想要做的事情:

参与者最初被分为八组,每组四名参与者。我想将每个参与者随机重新分配到一个新组,但我不希望任何参与者最终与来自同一原始组的另一个参与者一起加入新组。

这是我的进展:

import random
import pandas as pd
import itertools as it

data = list(it.product(range(8),range(4)))
test_df = pd.DataFrame(data=data,columns=['group','partid'])
test_df['new_group'] = None

for idx, row in test_df.iterrows():
    start_group = row['group']
    takens      = test_df.query('group == @start_group')['new_group'].values
    fulls       = test_df.groupby('new_group').count().query('partid >= 4').index.values
    possibles   = [x for x in test_df['group'].unique() if (x not in takens)
                                                      and (x not in fulls)]
    test_df.loc[idx,'new_group'] = random.choice(possibles)

这里的基本想法是,我将参与者随机重新分配到一个新组,其约束条件是(a)新组中没有原始组伙伴之一,并且(b)新组中没有已重新分配 4 个或更多参与者。

这种方法的问题在于,很多时候,当我们尝试重新分配最后一个组时,唯一剩余的组槽位位于同一组中。我也可以在失败时尝试重新随机化,直到成功为止,但这感觉很愚蠢。另外,我想进行 100 次随机重新分配,因此这种方法可能会变得非常慢......

所以必须有一种更聪明的方法来做到这一点。我还觉得应该有一种更简单的方法来解决这个问题,因为目标感觉很简单(但我意识到这可能会产生误导......)

最佳答案

编辑:更好的解决方案

<小时/>

经过深思熟虑,我发现了一个明显更好的解决方案,位于~ Big O of numGroups

示例数据

import random
import numpy as np
import pandas as pd
import itertools as it

np.random.seed(0)
numGroups=4
numMembers=4

data = list(it.product(range(numGroups),range(numMembers)))
df = pd.DataFrame(data=data,columns=['group','partid'])

解决方案

g = np.repeat(range(numGroups),numMembers).reshape((numGroups,numMembers))
In [95]: g
Out[95]: 
array([[0, 0, 0, 0],
       [1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3]])

g = np.random.permutation(g)
In [102]: g
Out[102]: 
array([[2, 2, 2, 2],
       [3, 3, 3, 3],
       [1, 1, 1, 1],
       [0, 0, 0, 0]])

g = np.tile(g,(2,1))
In [104]: g
Out[104]: 
array([[2, 2, 2, 2],
       [3, 3, 3, 3],
       [1, 1, 1, 1],
       [0, 0, 0, 0],
       [2, 2, 2, 2],
       [3, 3, 3, 3],
       [1, 1, 1, 1],
       [0, 0, 0, 0]])

注意对角线。

array([[2, -, -, -],
       [3, 3, -, -],
       [1, 1, 1, -],
       [0, 0, 0, 0],
       [-, 2, 2, 2],
       [-, -, 3, 3],
       [-, -, -, 1],
       [-, -, -, -]])

从上到下画对角线。

newGroups = []
for i in range(numGroups):
    newGroups.append(np.diagonal(g[i:i+numMembers]))

In [106]: newGroups
Out[106]: 
[array([2, 3, 1, 0]),
 array([3, 1, 0, 2]),
 array([1, 0, 2, 3]),
 array([0, 2, 3, 1])]

newGroups = np.ravel(newGroups)
df["newGroups"] = newGroups

In [110]: df
Out[110]: 
    group  partid  newGroups
0       0       0          2
1       0       1          3
2       0       2          1
3       0       3          0
4       1       0          3
5       1       1          1
6       1       2          0
7       1       3          2
8       2       0          1
9       2       1          0
10      2       2          2
11      2       3          3
12      3       0          0
13      3       1          2
14      3       2          3
15      3       3          1

旧解决方案:暴力法

<小时/>

结果比我想象的要困难得多......

我有一种蛮力方法,基本上可以猜测组的不同排列,直到最终得到一个每个人最终都在不同组中的排列。与您所展示的方法相比,这种方法的好处是它不会遭受“最后用完组”的问题。

它可能会变慢 - 但对于 8 个组和每个组 4 个成员来说,速度很快。

示例数据

import random
import numpy as np
import pandas as pd
import itertools as it

random.seed(0)
numGroups=4
numMembers=4

data = list(it.product(range(numGroups),range(numMembers)))
df = pd.DataFrame(data=data,columns=['group','partid'])

解决方案

g = np.repeat(range(numGroups),numMembers).reshape((numGroups,numMembers))

In [4]: g
Out[4]: 
array([[0, 0, 0, 0],
       [1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3]])

def reArrange(g):
    g = np.transpose(g)
    g = [np.random.permutation(x) for x in g]
    return np.transpose(g)

# check to see if any members in each old group have duplicate new groups
# if so repeat
while np.any(np.apply_along_axis(lambda x: len(np.unique(x))<numMembers,1,g)):
    g = reArrange(g)

df["newGroup"] = g.ravel()

In [7]: df
Out[7]: 
    group  partid  newGroup
0       0       0         2
1       0       1         3
2       0       2         1
3       0       3         0
4       1       0         0
5       1       1         1
6       1       2         2
7       1       3         3
8       2       0         1
9       2       1         0
10      2       2         3
11      2       3         2
12      3       0         3
13      3       1         2
14      3       2         0
15      3       3         1

关于python - 将参与者随机重新分配到组中,以便最初来自同一组的参与者最终不会出现在同一组中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42602014/

相关文章:

python - 如何在 ArtistAnimation 中显示更改子图标签 (plt.text) 的进度以及颜色变化

python - 如何在 pandas 中沿着时间戳对总和进行分组?

python - 在 str.split 操作后创建一个包含最后 2 个值的新列

algorithm - 什么是好的一次性伪随机洗牌?

c# - 这是生成一串随机字符的好方法吗?

c - 为什么第二个数组写的是愚蠢的数字? - C语言

python - 缓存访问被拒绝。请求模块中需要身份验证

python - “模块”对象没有属性 'unescape'

python - 如何循环时间戳并创建 df

python - 循环 web.client.getPage 函数时内存泄漏