0

我正在为我将在我的硕士论文中运行的实验编写代码。我基本上完成了,但我被困在最后一个方面,我找不到解决方法。我有一个公益游戏,有 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
4

2 回答 2

1

我不是 100% 确定我遇到了问题,但是如果我建议任务是在受试者内设计中随机化治疗顺序,那么每个玩家将每个治疗玩 3 次,但是这个顺序应该在玩家之间随机化. 然后我认为可以这样做:

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 方式来做,但为了懒惰它可以工作)。

然后当 eachSubsession启动时,你会得到这个列表列表,对于每个组,我们将它们打乱(每个子列表中的项目不打乱),然后将它们弄平,所以它只是一个列表。之后我们添加这个打乱的列表在会话级别对列表(列表)的治疗。

因此,在treatments会话变量的第一轮之后,您将获得每组所有治疗的完整数组。

然后您只需将treatment模型中的模型字段设置为Group等于个性化治疗列表中的项目,对应于当前轮次和组 ID。

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

于 2017-06-25T13:35:27.697 回答
0

我决定添加另一个答案而不是编辑前一个答案,因为如果您不需要重新调整组,第一个答案仍然会有所帮助。

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

有以下三个条件:

  1. 条件1:玩家从这组随机治疗三轮,然后下一个(随机)治疗三轮,依此类推。

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

  2. 条件 2:每轮恰好有四名球员打相同的待遇。

  3. 条件3:改组。这意味着根本没有球员在所有回合中具有完全相同的治疗顺序。因此,如果有人玩 AAABBBCCCDDD,没有人可以这样做,并且要成为前三轮 A 的四个玩家之一,另一个玩家需要有类似 AAABBBDDDCCC 的东西。

由于人们总是连续玩三轮(如 AAA 或 BBB),让我们将三元组 AAA 描述为A等 - 只是为了简洁起见。所以 AAABBBCCCDDD 将是ABCD

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

该代码与最佳代码相差甚远,我相信更有经验的 python 程序员会轻松地以更高效的方式进行操作。但它有效。您需要做的只是将此矩阵分配给任何session.vars变量,然后每个玩家都可以根据他的 id 和回合数获得他/她的治疗。

函数by_letters比较两个序列,True如果在两个序列的相同位置至少有一个字母,则返回。所以它返回和True因为,但它返回和。abcdbdcacFalseabcdbadc

我们在一开始就生成了我们四种处理方法的所有(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)

输出类似于:

...
['aaabbbdddccc', 'dddcccaaabbb', 'cccdddbbbaaa', 'bbbaaacccddd', 
'cccdddaaabbb', 'aaabbbcccddd', 'bbbaaadddccc', 'dddcccbbbaaa', 
'aaacccbbbddd', 'dddaaacccbbb', 'cccbbbdddaaa', 'bbbdddaaaccc', 
'dddaaabbbccc', 'bbbdddcccaaa', 'aaacccdddbbb', 'cccbbbaaaddd']
于 2017-06-26T12:17:10.483 回答