oT随机治疗的有效方法

2024-05-06 14:45:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在写我要在硕士论文中进行的实验的代码。我基本上已经完成了,但最后一个问题我无法找到解决的方法。我有一个公益游戏,有16个参与者,分成8个两组。我有4个治疗,我平衡了比赛,每一个治疗是由4个球员每轮(他们是12)。我现在缺少的是我希望每个球员每轮都能打3次。这个随机化是在下面的代码中执行的,理论上是可行的,但实际上我从来没有设法结束它。在20分钟内,我设法在第10轮结束时得到,但未能使程序找到满足上述第11轮和第12轮两个条件的组合。我知道这有点棘手,如果你喜欢的话更容易理解,但是。。。你有什么建议吗? 谢谢!在

class Subsession(BaseSubsession):

    def before_session_starts(self):
        info_condition = ['Bel', 'Bel', 'Act', 'Act', 'Ctrl', 'Ctrl', 'No', 'No']
        i = 0
        condition = True
        while condition:
            i+= 1
            print('I am in the loop: {} th time. Round{}.'.format(i, self.round_number))
            self.group_randomly()
            for gr_index, g in enumerate(self.get_groups()):
                g.info = info_condition[gr_index]
                for p in g.get_players():
                    p.info_player = g.info

            condition = any(not p.can_go_on(p.info_player) for p in self.get_players())
            if condition == False:
                break
        p.count_treat()
        print('I am out of the loop. Round{}'.format(self.round_number))

class Player(BasePlayer):

    runs = models.CharField()

    def count_treat(self):
        ctrl_count = 0
        no_count = 0
        bel_count = 0
        act_count = 0
        for p in self.in_all_rounds():
            if p.info_player == "Ctrl":
                ctrl_count += 1
            elif p.info_player == "No":
                no_count += 1
            elif p.info_player == "Bel":
                bel_count += 1
            elif p.info_player == "Act":
                act_count += 1
            p.runs = dict()
            p.runs['Ctrl'] = ctrl_count
            p.runs['Bel'] = bel_count
            p.runs['No'] = no_count
            p.runs['Act'] = act_count


    def can_go_on(self, activity):
        self.count_treat()
        print(self.id_in_subsession, self.runs[activity] < 4, activity, self.runs[activity])
        return self.runs[activity] < 4

Tags: noinselfinfofordefcountruns
2条回答

我决定添加另一个答案,而不是编辑前一个答案,因为第一个答案在您不需要重组组的情况下仍然是有用的。在

所以,假设你有四种治疗方法-[A,B,C,D]

有三个条件:

  1. 条件1:玩家从这一组中随机进行3轮治疗,然后进行下一个(随机)治疗3回合等

    我们可以将一个特定玩家的序列描述为一个列表:aaabbbccddd,其中一个字母对应于一个治疗,它在这个字符串中的位置对应于一个整数。

  2. 条件2:每一轮比赛中,有四名选手进行相同的治疗。

  3. 条件3:改组。这意味着没有任何球员在所有回合中都有完全相同的治疗顺序。所以,如果有人玩aaabbbccddd,没有人可以做同样的事情,而且要想在前三轮中成为A的四个玩家之一,另一个玩家需要有类似aaabbbddccc的东西。在

因为人们总是连续打三个回合(比如AAA,或者BBB),为了简洁起见,让我们把三连体AAA描述为a,等等。因此aaabbbccddd将是ABCD。在

下面的代码生成一个12X16矩阵,每个玩家连续播放三次每个治疗,并且满足所有3个条件。在

代码远远不是最优的,我相信经验丰富的python程序员可以很容易地以一种更高效的方式来实现这一点。但它是有效的。您只需将这个矩阵赋给任何session.vars变量,然后每个玩家就可以根据自己的id和整数获得他/她的治疗。在

函数by_letters比较两个序列,如果两个序列中的同一位置至少有一个字母,则返回True。因此它返回abcdbdcaTrue,因为c,但它返回{}和badcFalse。在

我们在开始时生成了我们四种治疗方法的所有(24)种可能的排列。这是我们可以使用的序列库。在

函数filtered返回没有一致字母的可用序列的子集(基于by_letters函数)。在

当找到治疗矩阵时,triple函数只会重复每个治疗3次。在

因此,我们通过从我们的一组处理中产生排列来获得初始数据。在

我们从中选取一个随机序列,然后根据第一次绘制筛选出剩余的数据。这是我们的第二个序列。在

我们发现了两个集合的交集,这两个集合的字母都不与序列1和序列2都重合。然后从剩下的子集中我们画了一条随机线。这是我们的第三个序列。在

我们做同样的三个集合的交集来得到第四个序列。 这是我们的第一个4X4矩阵。 我们从初始数据中过滤出所有的序列(通过使用itertools.filterfalse),并使用初始数据循环四次,但是没有我们刚刚找到的序列。在

由于并非每次都能找到4个满足所有条件的4X4矩阵,我们用try.. except..来绘制另一个随机起始序列。在

import random
import itertools
initial_data = list(itertools.permutations('abcd'))

def by_letters(a, b):
    u = zip(a, b)
    for i, j in u:
        if i == j:
            return True
    return False


def filtered(what):
    x = [i for i in a if not by_letters(i, what)]
    return x


def triple(str):
    return ''.join([c+c+c for c in str])

result = None

while result is None:
    try:
        matrices = []
        a = initial_data
        for i in range(4):
            print('cycle:: ', i)
            line1 = random.choice(a)
            line2 = random.choice(filtered(line1))
            s1 = set(filtered(line1))
            s2 = set(filtered(line2))
            sets = [s1, s2]
            line3 = random.choice(list(set.intersection(*sets)))
            s3 = set(filtered(line3))
            sets = [s1, s2, s3]
            line4 = random.choice(list(set.intersection(*sets)))
            matrix1 = [line1, line2, line3, line4]
            matrices.append(matrix1)
            a = list(itertools.filterfalse(lambda x: x in matrix1, a))
        result = matrices                

    except IndexError:
         pass

final = [triple(j) for i in matrices for j in i]
print(final)

输出是这样的:

^{pr2}$

我不是百分之百确定我有问题,但如果我建议任务是在受试者设计中随机选择治疗顺序,那么每个玩家将在每种治疗中玩三次,但这个顺序应该在玩家之间随机进行。我想可以这样做:

models.py中:

import random
class Constants(BaseConstants):
      treatments = [['Bel', 'Bel','Bel'],
             ['Act', 'Act', 'Act'],
             ['Ctrl', 'Ctrl', 'Ctrl'],
             ['No', 'No', 'No']]

class Subsession(BaseSubsession):
def before_session_starts(self):
    if not self.session.vars.get('treatments'):
        treatments = []
        for g in self.get_groups():
            group_treatments = Constants.treatments
            random.shuffle(group_treatments)
            flat_treatments = [item for sublist in group_treatments for item in sublist]
            if g.id % 2 != 0:
                treatments.append(flat_treatments)
            else:
                treatments.append(treatments[-1])
        self.session.vars['treatments'] = treatments

    for g in self.get_groups():
        g.treatment = self.session.vars['treatments'][g.id - 1][g.round_number - 1]

我们在这里做什么? 在Constants中,我们创建了一个包含一组处理方法的列表(不是最优雅的方式,因此如果您需要改变轮次的长度,可以用更python的方式来做,但出于懒惰的考虑,它起作用了)。在

然后,当每个Subsession被启动时,您将获得这个列表列表,对于每个组,我们将它们洗牌(每个子列表中的项目那时不会被洗牌),然后使它们变平,因此它只是一个列表。之后我们将这个随机处理的列表添加到会话级别的(列表)列表中。在

因此,在treatments会话变量中的第一轮之后,您就有了每个组所有治疗的完整数组。在

然后您只需将treatment模型中的treatment字段设置为个性化治疗列表中的项目,对应于当前回合和组id

更新:使两组的治疗顺序相同

相关问题 更多 >