11

心理学の実験では、多くの場合、試行順序を疑似ランダム化する必要があります。これにより、試行がランダムに見えるようになりますが、同様の試行が連続して多くなりすぎることはありません (純粋にランダムな順序で発生する可能性があります)。

各トライアルの視覚的表示に色とサイズがあるとします。

display_list = []
colours = {0: 'red', 1: 'blue', 2: 'green', 3: 'yellow'}
sizes = [1] * 20 + [2] * 20 + [3] * 20 + [4] * 20 + [5] * 20 + [6] * 20
for i in range(120):
    display_list.append({'colour': colours[i % 4], 'size': sizes[i]})
print(display_list)

そして、この関数を使用して、いずれかのプロパティに対して同じ値を持つ連続試行の最大数を確認できます。

def consecutive_properties(seq, field):
    longest_run = 0
    prev_value = None
    current_run = 0
    for d in seq:
        if d[field] == prev_value:
            current_run += 1
        else:
            current_run = 1
        if current_run > longest_run:
            longest_run = current_run
        prev_value = d[field]
    return longest_run

出力:

>>> print("Consecutive colours: ", consecutive_properties(display_list, 'colour')
('Consecutive colours: ', 1)

>>> print("Consecutive sizes: ", consecutive_properties(display_list, 'size'))
('Consecutive sizes: ', 20)

いずれかまたは両方のプロパティの連続した実行を最小限に抑える、または少なくともこれらの実行を指定された長さ未満に保つことを可能にする、あなたが知っているアルゴリズムはありますか? 後者の場合、同じ色またはサイズの行で 4 つ以下としましょう。


私が試したこと:

私が今持っている解決策は、基本的には少しインテリジェントなbogosortを実行しますが、これは恐ろしく非効率的でなければなりません。基本的:

  • リスト全体を、プロパティのすべての順列を含むチャンクに分割します。display_list長さ 24 のチャンクに分割すると、各チャンクには各色と各サイズのペアが含まれます。実験の設計から順列が何であるかを知っているので、試行リストは常にこれらの順列チャンクに分割できると仮定しましょう。
  • チャンクごとの最大実行長を選択します
  • 各チャンクの実行の長さが最大値を下回るまで、各チャンクをシャッフルします (これは実際には、1 つのチャンクの最後にこの長さの実行がある可能性があるため、試行リスト全体で、実行がその長さの 2 倍になる可能性があることを意味します)。そして次の始まり)
4

5 に答える 5

3

質問: いずれかまたは両方のプロパティの連続した実行を最小限に抑える、または少なくともこれらの実行を指定された長さ未満に保つことを可能にするアルゴリズムを知っていますか?

はい。これを行うための簡単なアルゴリズムがあります。これは、ランで既に発生している場合に、色またはサイズが選択される可能性を単純に減らすことによって行われます。

from random import randrange

def choose(colors, numselections, maxrun):
    'Repeatedly choose colors.  Gradually reduce selection probability to avoid runs.'
    colors = list(colors)
    n = len(colors)
    total = n * maxrun
    current_run = 0
    for _ in range(numselections):
        i = randrange(total - current_run) // maxrun
        yield colors[i]
        colors[i], colors[-1] = colors[-1], colors[i]
        current_run = current_run + 1 if i==n-1 else 1

if __name__ == '__main__':
    colors = ['red', 'blue', 'green', 'yellow']
    for color in choose(colors, 100, maxrun=4):
        print color

このアプローチは、再選択手法を使用して実行を回避する他の回答よりも労力が少なくて済むことに注意してください。また、実行は、他の回答のように一度にではなく、徐々にフェードアウトすることに注意してください。

于 2013-05-27T09:10:39.467 に答える
1

連続する要素の可能性が非常に高くない場合 (あなたの例のように)、条件が満たされない場合は単に再シャッフルします。ご覧のとおり、ほとんどの場合、1 回の試行で回避できるため、非常に効率的です。

In [1]: from random import shuffle

In [2]: from itertools import groupby

In [3]: from collections import Counter

In [4]: def pseudo_shuffle(lst, limit, tries=1):
   ...:     temp = list(lst)
   ...:     shuffle(temp)
   ...:     if max(sum(1 for x in g) for k, g in groupby(temp)) <= limit:
   ...:         return tries #return temp
   ...:     return pseudo_shuffle(lst, limit, tries=tries+1)

In [5]: colors = 30*['red', 'blue', 'green', 'yellow']

In [6]: sizes = [1] * 20 + [2] * 20 + [3] * 20 + [4] * 20 + [5] * 20 + [6] * 20

In [7]: Counter([pseudo_shuffle(colors, 4) for _ in range(1000)])
Out[7]: Counter({1: 751, 2: 200, 3: 38, 4: 10, 5: 1})

In [8]: Counter([pseudo_shuffle(sizes, 4) for _ in range(1000)])
Out[8]: Counter({1: 954, 2: 44, 3: 2})
于 2013-05-27T06:30:19.760 に答える
1

真のランダム性のようなものは明らかに気にしていないので、距離メトリックを定義してシーケンスをランダムに描画すると、距離が前の描画に「近すぎる」場合は新しい描画を拒否し、単純にもう一度描画できます。

有限セット (たとえば、カードのパック) からドローしている場合、セット全体がドロー パイルになる可能性があり、並べ替えは、近いペアが見つかったときに 2 つの要素を交換することで構成されますが、次の場合はスワップ パートナーも拒否します。交換された要素は受け入れられなくなるため、各交換ステップでセット全体が改善されたままになります。

基準を満たすのがそれほど難しくない場合、これはすぐに終了します。

于 2013-05-27T05:52:57.733 に答える
0

申し訳ありませんが、回答ではありませんが、コメントにコードを投稿するのは難しいです。consecutive_propertiesこれは、関数を書くためのより簡単な方法です

from operator import itemgetter
from itertools import groupby
def consecutive_properties(seq, field):
    return max(sum(1 for x in g) for k,g in groupby(seq, key=itemgetter(field)))

あなたの質問を正しく理解したら、これを答えに変えようとします:)

于 2013-05-27T05:32:00.213 に答える