我有Knuth's shuffling algorithm的简å•Python实现:
def knuth_shuffle(ar):
num = len(ar)
for i in range(num):
index = random.randint(0, i)
ar[i], ar[index] = ar[index], ar[i]
return ar
如何测试(使用scipy
æˆ–å…¶ä»–ä»»ä½•åŒ…ï¼‰æ´—ç‰Œç¡®å®žæ˜¯ç»Ÿä¸€çš„ï¼Ÿæˆ‘æ‰¾åˆ°äº†å‡ ä¸ªç›¸å…³çš„å¸–å(1,2),但他们没有回ç”我的问题。一般æ¥è¯´ï¼Œäº†è§£å¦‚何执行æ¤ç±»æ£€æŸ¥ä¼šå¾ˆæ£’。
ç”案 0 :(得分:2)
编辑:
作为评论ä¸çš„Paul Hankin,我的原始测试åªæ£€æŸ¥äº†æ¯ä¸ªå…ƒç´ è½å…¥æ¯ä¸ªä½ç½®çš„概率,而ä¸æ˜¯æ‰€æœ‰æŽ’列都是åŒç‰å¯èƒ½çš„,这是一个更强烈的è¦æ±‚。下é¢çš„代ç 段计算æ¯ä¸ªæŽ’列的频率,这是我们应该看到的:
import math
import random
def knuth_shuffle(ar):
num = len(ar)
for i in range(num):
index = random.randint(0, i)
ar[i], ar[index] = ar[index], ar[i]
return ar
# This function computes a unique index for a given permutation
# Adapted from https://www.jaapsch.net/puzzles/compindx.htm#perm
def permutation_index(permutation):
n = len(permutation)
t = 0
for i in range(n):
t = t * (n - i)
for j in range(i + 1, n):
if permutation[i] > permutation[j]:
t += 1
return t
N = 6 # Test list size
T = 1000 # Trials / number of permutations
random.seed(100)
n_perm = math.factorial(N)
trials = T * n_perm
ar = list(range(N))
freq = [0] * n_perm
for _ in range(trials):
ar_shuffle = ar.copy()
knuth_shuffle(ar_shuffle)
freq[permutation_index(ar_shuffle)] += 1
如果éšæœºæ’放是统一的,则生æˆçš„freq
å‘é‡çš„å€¼åº”æ ¹æ®å…·æœ‰T * N!
次试验的二项分布和æˆåŠŸæ¦‚率1 / (N!)
进行分é…。以下是上一个示例(使用Seaborn完æˆï¼‰çš„分布估计图,其ä¸é¢‘率值应为1000å·¦å³ï¼š
我认为看起æ¥å¥½ä½†æ˜¯ï¼Œå¯¹äºŽå®šé‡ç»“果,您需è¦è¿›è¡Œæ›´æ·±å…¥çš„统计分æžï¼Œä¾‹å¦‚Pearson's chi-squared test建议的David Eisenstat。
原始ç”案:
我将在这里æ出一些基本的想法,但我没有最强的统计背景,所以有人å¯èƒ½æƒ³è¦è¡¥å……æˆ–çº æ£ä»»ä½•é”™è¯¯ã€‚
您å¯ä»¥å°†æ¯ä¸ªå€¼çš„频率矩阵放入æ¯ä¸ªä½ç½®è¿›è¡Œå¤šæ¬¡è¯•éªŒï¼š
def knuth_shuffle(ar):
num = len(ar)
for i in range(num):
index = random.randint(0, i)
ar[i], ar[index] = ar[index], ar[i]
return ar
N = 100 # Test list size
T = 10000 # Number of trials
ar = list(range(N))
freq = [[0] * N for _ in range(N)]
for _ in range(T):
ar_shuffle = ar.copy()
kunth_shuffle(ar_shuffle)
for i, j in enumerate(ar_shuffle):
freq[i][j] += 1
ä¸€æ—¦ä½ èƒ½åšåˆ°è¿™ä¸€ç‚¹ï¼Œä½ å¯ä»¥é‡‡å–å‡ ç§æ–¹æ³•ã€‚一个简å•çš„想法是,如果洗牌是统一的,freq / T
应倾å‘于1 / N
ï¼Œå› ä¸ºT
倾å‘äºŽæ— ç©·å¤§ã€‚æ‰€ä»¥ä½ å¯ä»¥ä½¿ç”¨ä¸€ä¸ªéžå¸¸å¤§çš„"值T
并看到这些值足够接近"。或者检查freq / T - 1 / N
çš„æ ‡å‡†å差是å¦è¶³å¤Ÿå°ï¼†ï¼ƒ34;。
这些"足够接近"并且"足够å°ï¼†ï¼ƒ34;虽然ä¸æ˜¯å¾ˆæ‰Žå®žçš„概念。基础分æžéœ€è¦æ›´å¤šç»Ÿè®¡å·¥å…·ã€‚我认为您需è¦test the hipothesisæ¯ä¸ªé¢‘率值都æ¥è‡ªbinomial distribution T
次试验1 / N
æˆåŠŸæ¦‚率。æ£å¦‚我所说,没有完整解释的背景,这å¯èƒ½ä¸é€‚åˆå®ƒï¼Œä½†å¦‚æžœä½ çœŸçš„éœ€è¦å½»åº•çš„分æžï¼Œä½ å¯ä»¥é˜…读这个主题。
ç”案 1 :(得分:2)
您å¯ä»¥é€šè¿‡å°†æ‰€æœ‰å¯èƒ½çš„éšæœºæ•°åºåˆ—注入knuth_shuffle
æ¥æ£€æŸ¥è¿™ä¸€ç‚¹ï¼Œç„¶åŽéªŒè¯æ‚¨æ˜¯å¦åªéœ€å‡†å¤‡ä¸€æ¬¡ã€‚
æ¤ä»£ç 执行æ¤æ“作:
import collections
import itertools
import random
def knuth_shuffle(ar, R=random.randint):
num = len(ar)
for i in range(num):
index = R(0, i)
ar[i], ar[index] = ar[index], ar[i]
return ar
def fact(i):
r = 1
while i > 1:
r *= i
i -= 1
return r
def all_random_seqs(N):
for r in range(fact(N)):
seq = []
for i in range(N):
seq.append(r % (i+1))
r //= (i+1)
it = iter(seq)
yield lambda x, y: next(it)
for N in range(1, 6):
print N
results = collections.Counter()
for R in all_random_seqs(N):
a = list('ABCDEFG'[:N])
knuth_shuffle(a, R)
results[''.join(a)] += 1
print 'checking...'
if len(results) != fact(N):
print 'N=%d. Not enough results. %s' % (N, results)
if any(c > 1 for c in results.itervalues()):
print 'N=%d. Not all permutations unique. %s' % (N, results)
if any(sorted(c) != list('ABCDEFG'[:N]) for c in results.iterkeys()):
print 'N=%d. Some permutations are illegal. %s' % (N, results)
æ¤ä»£ç 检查大å°ä¸º1,2,3,4,5的输入列表的确切æ£ç¡®æ€§ã€‚您å¯ä»¥åœ¨N之å‰å†è¿œä¸€ç‚¹ï¼å¤ªå¤§äº†ã€‚
您还希望使用random.randint
对代ç 版本执行完整性检查(例如,生æˆ500次'ABCD',并确ä¿æ¯æ¬¡æŽ’列至少一次。)
ç”案 2 :(得分:0)
如果您从给定的固定订å•ä¸éšæœºæ´—牌相åŒçš„商å“,则éšæœºå•†å“ä¸ä¸€ä¸ªå›ºå®šä½ç½®ä¸æ¯ä¸ªå•†å“çš„æ•°é‡åº”该趋å‘于相åŒçš„值。
下é¢æˆ‘将列表0..9æ´—ç‰Œå‡ æ¬¡å¹¶æ‰“å°è¾“出:
from random import shuffle # Uses Fischer-Yates
tries = 1_000_000
intcount = 10
first_position_counts = {n:0 for n in ints}
ints = range(intcount)
for _ in range(tries):
lst = list(ints) # [0, 1, ...9] In that order
shuffle(lst)
first_position_counts[lst[0]] += 1
print(f'{tries} shuffles of the ints 0..{intcount-1} should have each int \n',
'appear in the first position {tries/intcount} times.')
for item in first_position_counts.items():
print(' %i: %5i' % item)
è¿è¡Œä¸€æ¬¡ï¼Œä½ å¯èƒ½å¾—到类似的东西:
0: 99947 1: 100522 2: 99828 3: 100123 4: 99582 5: 99635 6: 99991 7: 100108 8: 100172 9: 100092
å†æ¬¡ï¼š
0: 100049 1: 99918 2: 100053 3: 100285 4: 100293 5: 100034 6: 99861 7: 99584 8: 100055 9: 99868
çŽ°åœ¨ï¼Œå¦‚æžœä½ æœ‰æ•°ä»¥åƒè®¡çš„项目è¦æ´—牌,那么它们应该以{{1​​}}排列之一结æŸï¼Œä½†æ˜¯n!
å˜å¤§ï¼Œå¼ºå¤§;如果它是“å¯æ¯”较的â€ï¼Œè‚¯å®šæ¯”ä½ çš„éšæœºæ•°å‘生器的å¯èƒ½èŒƒå›´æ›´å¤§ï¼Œé‚£ä¹ˆå®ƒå°±ä¼šå´©æºƒã€‚