이 "순진한"셔플 링 알고리즘에 어떤 문제가 있습니까?


23

이것은 배열을 무작위로 섞는 것에 대한 Stackoverflow 질문에 대한 후속 조치 입니다.

"순진한"임시 구현에 의존하기보다는 배열을 섞기 위해 사용해야하는 확립 된 알고리즘 (예 : Knuth-Fisher-Yates Shuffle )이 있습니다.

이제 내 순진 알고리즘이 손상되었다는 것을 증명 (또는 반증)하는 데 관심이 있습니다 (같은 확률로 가능한 모든 순열을 생성하지는 않음).

알고리즘은 다음과 같습니다.

몇 번 반복 (배열 길이해야 함)하고 반복 할 때마다 두 개의 임의 배열 인덱스를 가져 와서 두 요소를 바꿉니다.

분명히, 이것은 KFY보다 더 많은 난수를 필요로하지만 (2 배) 그 외에는 제대로 작동합니까? 그리고 적절한 반복 횟수는 얼마입니까 ( "배열 길이"이면 충분합니까)?


4
나는 사람들이 왜이 교환식이 FY보다 '단순하거나'보다 순진하다고 생각하는지 이해할 수 없습니다 ...이 문제를 처음 해결했을 때 FY를 구현했습니다 (이름조차 알지 못합니다) , 그것이 나를 위해 그것을하는 가장 간단한 방법처럼 보였기 때문입니다.

1
@ mbq : 개인적으로, 나는 FY가 나에게 더 "자연스러워 보인다"는 것에 동의하지만 그것들이 똑같이 쉽다는 것을 알았습니다.
니코

3
내 자신을 작성한 후에 셔플 링 알고리즘을 연구했을 때 (내가 버린 연습), 나는 모두 "거룩한 쓰레기, 완료되었으며 이름이 있습니다 !"
JM은 통계학자가 아닙니다.

답변:


12

충분한 셔플을 수행하면 이전의 답변에서 알 수 있듯이 훌륭한 근사치 일 수 있습니다.

그냥 무슨 일이 일어나고 있는지에 대한 핸들을 얻기 위해, 알고리즘이의 셔플 생성 빈도를 고려 첫 번째 요소가 고정되는 요소의 배열, K 2 . 동일한 확률로 순열이 생성되면 1 / k 의 시간이 발생합니다. 하자 P는 N 후이 사건의 상대 빈도 수 n 개의 알고리즘과 셔플을. 관대하고, 셔플에 대해 무작위로 서로 다른 인덱스 쌍을 무작위로 균일하게 선택하여 각 쌍이 확률 1 / ( kkk21/kpnn =2/(k(k-1)). (이것은 "사소한"셔플이 낭비되지 않았 음을 의미합니다. 반면에, 그것은 두 요소를 고정하는 것과 교체하는 것 사이에서 번갈아 가며, 따라서 미리 결정된 수의 단계, 결과에 대한 임의성이 없습니다!)1/(k2)2/(k(k1))

첫 번째 요소는 두 개의 분리 된 방식으로 셔플 후 원래 위치에서 발견되므로이 빈도는 간단한 반복을 만족시킵니다 . 하나는 셔플 후에 고정되었고 다음 셔플은 첫 번째 요소를 움직이지 않는다는 것입니다. 다른 하나는 셔플 후 이동 되었지만 셔플은 다시 이동한다는 것입니다. 첫 번째 요소를 이동할 수 없는 확률 은 = 와 같지만 첫 번째 요소를 다시 이동할 가능성은 와 같습니다 = 입니다. 어떻게:n n n + 1 s t ( k 1n+1nnn+1s (k2)/k1/ ( k(k12)/(k2)(k2)/k 2/(k(k-1))1/(k2)2/(k(k1))

p0=1
첫 번째 요소가 올바른 위치에서 시작하기 때문에 ;

pn+1=k2kpn+2k(k1)(1pn).

해결책은

pn=1/k+(k3k1)nk1k.

빼면 주파수가 잘못되었음을 알 수 있습니다. 와 큰 경우 근사값은 입니다. 이는 이 특정 주파수 의 오류 어레이의 크기 ( )에 비해 스왑 수에 따라 기하 급수적으로 감소 하여 비교적 많은 수의 스왑을 수행 한 경우 큰 배열로는 감지하기 어렵다는 것을 나타냅니다 -하지만 오류는 항상 있습니다.1/k(k3k1)nk1kknk1kexp(2nk1)n/k

모든 주파수의 오차에 대한 포괄적 인 분석을 제공하기는 어렵습니다. 그것은 그 어떤 쇼,하지만 가능성이 그들이 이와 같은 행동 윌의 최소한 당신이 필요 오류가 수용 가능한 작은 수 있도록 충분한 수 (스왑의 수). 대략적인 해결책은n

n>12(1(k1)log(ϵ))

여기서 1 / k에 비해 매우 작아야 합니다. 이는 균등 한 근사치에 대해서도 n 이 몇 배 k 여야 함을 의미 합니다 ( , 여기서 ϵ0.01 곱하기 1 / k 정도).ϵ1/knkϵ0.011/k

이 모든 것은 의문을 제기합니다. 왜 (정확히) 정확하지는 않지만 다른 알고리즘과 정확히 동일한 알고리즘을 사용하지만 더 많은 계산이 필요한 알고리즘을 사용하기로 선택한 이유는 무엇입니까?

편집하다

Thilo의 의견은 적절합니다 (그리고 아무도 이것을 지적하지 않기를 희망했기 때문에이 여분의 작업을 아끼지 않을 수 없었습니다!). 논리를 설명하겠습니다.

  • 매번 실제 스왑을 생성하면 완전히 망가집니다. 경우 에서 지적한 문제 는 모든 배열로 확장됩니다. 짝수의 스왑을 적용하면 가능한 모든 순열 중 절반 만 얻을 수 있습니다. 나머지 절반은 홀수의 스왑을 적용하여 얻습니다. 따라서이 상황에서는 순열의 균일 한 분포 근처에 아무 것도 생성 할 수 없습니다 (그러나 가능한 크기가 많은 k에 대한 시뮬레이션 연구 에서 문제를 감지 할 수없는 가능성이 너무 많습니다 ). 정말 나쁘다.k=2k

  • 따라서 두 위치를 임의로 임의로 생성하여 임의로 스왑을 생성하는 것이 좋습니다. 이것은 요소를 자신과 교체 할 때마다 기회 가 있음을 의미 합니다. 즉, 아무것도하지 않는 것입니다. 이 과정은 알고리즘의 속도를 약간 느리게합니다 : n 단계 후에 는 약 k - 1 만 기대합니다1/kn진정한 스왑이 발생했습니다.k1kN<N

  • 개별 스왑 수에 따라 오류 크기가 단조로 줄어 듭니다. 따라서 평균적으로 적은 수의 스왑을 수행하면 평균적으로 오류가 증가 합니다. 그러나 이것은 첫 번째 글 머리표에 설명 된 문제를 극복하기 위해 기꺼이 지불 해야하는 가격입니다. 결과적으로, 나의 오차 추정치는 대략 의 인자만큼 보수적으로 낮다 .(k1)/k

또한 흥미로운 명백한 예외를 지적하고 싶었습니다. 오류 공식을 자세히 보면 k = 3 인 경우 오류 가 없음을 나타 냅니다. 이것은 실수가 아닙니다. 맞습니다. 그러나 여기서는 순열의 균일 한 분포와 관련된 통계를 하나만 살펴 보았습니다. k = 3 일 때 (즉, 주어진 위치를 고정시키는 올바른 치환 빈도를 얻는) 알고리즘이이 하나의 통계량을 재현 할 수 있다는 사실 은 치환이 실제로 균일하게 분포되었음을 보장하지는 않습니다. 실제로 2 n 실제 스왑 후에 는 ( 123 ) , (k=3k=32n(123) 및 정체성. 후자 만 주어진 위치를 수정하므로 실제로 순열의 3 분의 1이 위치를 수정합니다. 그러나 순열의 절반이 빠져 있습니다! 다른 경우, 2 n + 1 실제 스왑후가능한 순열은 ( 12 ) , ( 23 ) ( 13 ) 뿐입니다. 다시 말하지만, 이들 중 정확히 하나가 주어진 위치를 고정하므로 해당 위치를 수정하는 올바른 치환 빈도를 다시 얻을 수 있지만 가능한 순열의 절반 만 얻습니다.(321)2n+1(12)(23)(13)

이 작은 예는 논쟁의 주요한 부분을 밝히는 데 도움이됩니다. "관대" 하여 하나의 특정 통계에 대한 오차율 을 보수적으로 과소 평가 합니다. 모든 대해 오류율이 0이 아니기 때문에 알고리즘이 고장난 것을 볼 수 있습니다. 또한, 이 통계 에 대한 오류율의 감소를 분석함으로써 우리 는 균일 한 순열의 분포를 근사화하기 위해 희망을 가질 필요가있는 알고리즘의 반복 횟수에 대한 하한 을 설정합니다 .k4


1
"너무 관대하고 실제로 셔플에 대해 무작위로 서로 다른 인덱스 쌍을 균일하게 선택한다고 가정합니다." 그 가정을 할 수있는 이유와 그 관대함을 이해하지 못합니다. 가능한 순열을 버리는 것처럼 보이며 임의 분포가 훨씬 적습니다.
Thilo

1
@Thilo : 감사합니다. 귀하의 의견은 확장 된 답변을받을 가치가 있으므로 답변 자체에 추가했습니다. 여기서 "관대 한"것은 실제로 어떤 순열도 버리지 않는다는 것을 지적하겠습니다 : 그것은 그렇지 않으면 아무것도하지 않는 알고리즘의 단계를 제거합니다.
whuber

2
이 문제는 순열 그룹의 Cayley 그래프에서 Markov 체인으로 완전히 분석 할 수 있습니다. K = 1 내지위한 수치 계산 7 (a 5,040 5,040 행렬!) (1, -1 후)의 크기가 가장 큰 고유 값을 정확하게인지 확인 . 이것은 당신이 순열의 부호를 교대의 문제를 대처 일단의 오류 (-1 고유치에 해당하는) 것을 의미 모든 확률이 속도로 붕괴 ( (1) - 2 /(k3)/(k1)=12/(k1) 이상입니다. 나는 이것이 더 큰 k 를 계속 유지한다고 생각한다. (12/(k1))nk
whuber

1
확률 클래스가 확률 클래스에서 변하지 않기 때문에 보다 훨씬 더 잘 수행 할 수 있으며 7의 15 개 파티션 만 있으므로 15 × 15 행렬을 대신 분석 할 수 있습니다 . 5040×504015715×15
Douglas Zare

8

숫자 셔플이 무한대에 가까워지면 간단한 알고리즘이 카드를 올바르게 셔플한다고 생각합니다.

{A, B, C} 카드가 3 개 있다고 가정합니다. 카드가 A, B, C 순서로 시작한다고 가정하십시오. 그런 다음 하나의 셔플 후에 다음 조합이 있습니다.

{A,B,C}, {A,B,C}, {A,B,C} #You get this if choose the same RN twice.
{A,C,B}, {A,C,B}
{C,B,A}, {C,B,A}
{B,A,C}, {B,A,C}

따라서, 카드 A가 {1,2,3} 위치에있을 확률은 {5/9, 2/9, 2/9}입니다.

카드를 두 번 섞으면 다음이 수행됩니다.

Pr(A in position 1 after 2 shuffles) = 5/9*Pr(A in position 1 after 1 shuffle) 
                                     + 2/9*Pr(A in position 2 after 1 shuffle) 
                                     + 2/9*Pr(A in position 3 after 1 shuffle) 

이것은 0.407을 제공합니다.

동일한 아이디어를 사용하여 재발 관계를 형성 할 수 있습니다.

Pr(A in position 1 after n shuffles) = 5/9*Pr(A in position 1 after (n-1) shuffles) 
                                     + 2/9*Pr(A in position 2 after (n-1) shuffles) 
                                     + 2/9*Pr(A in position 3 after (n-1) shuffles).

이것을 R로 코딩하면 (아래 코드 참조), 10 번의 셔플 후 카드 A가 {0.33334, 0.33333, 0.33333}으로 {1,2,3} 위치에있을 가능성이 있습니다.

R 코드

## m is the probability matrix of card position
## Row is position
## Col is card A, B, C
m = matrix(0, nrow=3, ncol=3)
m[1,1] = 1; m[2,2] = 1; m[3,3] = 1

## Transition matrix
m_trans = matrix(2/9, nrow=3, ncol=3)
m_trans[1,1] = 5/9; m_trans[2,2] = 5/9; m_trans[3,3] = 5/9

for(i in 1:10){
  old_m = m
  m[1,1] = sum(m_trans[,1]*old_m[,1])
  m[2,1] = sum(m_trans[,2]*old_m[,1])
  m[3,1] = sum(m_trans[,3]*old_m[,1])

  m[1,2] = sum(m_trans[,1]*old_m[,2])
  m[2,2] = sum(m_trans[,2]*old_m[,2])
  m[3,2] = sum(m_trans[,3]*old_m[,2])

  m[1,3] = sum(m_trans[,1]*old_m[,3])
  m[2,3] = sum(m_trans[,2]*old_m[,3])
  m[3,3] = sum(m_trans[,3]*old_m[,3])
}  
m

1
+1. 이는 주어진 카드가 주어진 위치에서 끝나는 확률이 셔플 수가 증가함에 따라 예상 비율에 근접 함을 보여줍니다. 그러나 배열을 임의의 양으로 한 번만 회전시키는 알고리즘의 경우에도 마찬가지입니다. 모든 카드는 모든 위치에서 끝날 확률이 동일하지만 여전히 임의성이 없습니다 (배열은 정렬 된 상태로 유지됨).
Thilo

@Thilo : 죄송합니다. 귀하의 의견을 따르지 않습니다. "알고리즘이 임의의 양만큼 회전하지만" "임의성 없음"이 있습니까? 더 설명해 주시겠습니까?
csgillespie

N 요소 배열을 0과 N-1 위치 (임의로) 사이에서 회전시켜 "셔플"하는 경우 모든 카드는 N 위치 중 하나에서 종료 될 확률이 정확히 동일하지만 2는 항상 1 사이에 있습니다 그리고
Thilo

1
@Thio : 아, 당신의 요점을 알 수 있습니다. 카드 B와 C의 경우 Pr (A 위치 2의 Pr)과 Pr (A의 위치 3)-확률은 (위와 정확히 동일한 아이디어를 사용하여) 계산할 수 있습니다. 모든 확률은 1/3. 참고 : 내 대답은 특별한 경우를 제공하지만 @whuber 좋은 대답은 일반적인 경우를 제공합니다.
csgillespie

4

완벽하게 균일 한 분포를 얻지 못하는 방법은 분 산성입니다. 균일 분포에서 각 순열의 확률은 . t 개의 무작위 전치 의 시퀀스를 생성 한 다음 그 곱으로 시퀀스를 수집 할 때 얻을 수있는 확률은 정수 A에 대해 A / n 2 t 형식 입니다. 만약 1 / N ! = A / n 2 t 이면 n 2 t / n ! = A1/!에이/2에이1/!=에이/22/!=에이. Bertrand의 Postulate (정리)에 의해 경우 분모에 발생하고 n을 나누지 않는 소수가 있으므로 n 2 t / n ! 는 정수가 아니며, 조옮김을 n으로 균등하게 나누는 방법이 없습니다 ! 순열. 예를 들어, N = 52 , 다음의 분모 1 / 52 ! 3 , 5 , 7 , 로 나눌 수 있습니다. . . , 47 분모가 1 /2/!!=521/52!,5,7,...,47 , 그래서 아니다 / 52 2 t는 로 줄일 수 1 / 52 ! .1/522에이/5221/52!

랜덤 순열을 근사화하려면 얼마나해야합니까? 랜덤 전치에 의한 랜덤 순열 생성은 Diaconis와 Shahshahani에 의해 대칭 그룹의 표현 이론을 사용하여 분석되었다.

Diaconis, P., Shahshahani, M. (1981) : "임의의 전치로 임의의 순열을 생성합니다." Z. Wahrsch. 대야 b. 57, 159–179.

한 가지 결론은 1 이 걸린다는 것입니다.이후에(1ϵ)1이라는 의미에서 2 nlogn전위12로그순열은 랜덤에서 멀지 만(1+ϵ)1 이후(1ϵ)12로그결과는 전체 변동 및L2거리의 관점에서 랜덤에 가깝습니다. 이 유형의 컷오프 현상은 그룹의 랜덤 워크에서 일반적이며데크가 랜덤에 가까워지기 전에7 개의리플 셔플이 필요한 유명한 결과와 관련이 있습니다.(1+ϵ)12로그27


2

나는 통계학자가 아니라는 것을 명심하지만 나는 2 센트를 넣을 것이다.

나는 R에서 약간의 테스트를했다 (주의, 그것은 매우 느리다 numTrials, 코드는 아마도 최적화 될 수있다) :

numElements <- 1000
numTrials <- 5000

swapVec <- function()
    {
    vec.swp <- vec

    for (i in 1:numElements)
        {
        i <- sample(1:numElements)
        j <- sample(1:numElements)

        tmp <- vec.swp[i]
        vec.swp[i] <- vec.swp[j]
        vec.swp[j] <- tmp
        }

    return (vec.swp)
    }

# Create a normally distributed array of numElements length
vec <- rnorm(numElements)

# Do several "swapping trials" so we can make some stats on them
swaps <- vec
prog <- txtProgressBar(0, numTrials, style=3)

for (t in 1:numTrials)
    {
    swaps <- rbind(swaps, swapVec())
    setTxtProgressBar(prog, t)
    }

이 매트릭스 생성 swapsnumTrials+1행 (시험 당 하나 + 일본어) 및 numElements열 (각 벡터 요소 하나씩). 방법이 올 바르면 각 열의 분포 (예 : 시험에서 각 요소의 값)는 원래 데이터의 분포와 달라야합니다.

원래 데이터가 정상적으로 분산되었으므로 모든 열이이 열에서 벗어나지 않을 것으로 예상합니다.

우리가 달리면

par(mfrow= c(2,2))
# Our original data
hist(swaps[1,], 100, col="black", freq=FALSE, main="Original")
# Three "randomly" chosen columns
hist(swaps[,1], 100, col="black", freq=FALSE, main="Trial # 1") 
hist(swaps[,257], 100, col="black", freq=FALSE, main="Trial # 257")
hist(swaps[,844], 100, col="black", freq=FALSE, main="Trial # 844")

우리는 얻는다 :

무작위 시행의 히스토그램

매우 유망 해 보입니다. 이제 분포를 통계적으로 확인하려면 원본에서 벗어난 것이 아닙니다. Kolmogorov-Smirnov 검정을 사용할 수 있다고 생각합니다 (일부 통계학자가 이것이 올바른지 확인할 수 있습니까?). 예를 들어

ks.test(swaps[1, ], swaps[, 234])

우리에게 p = 0.9926을줍니다

모든 열을 확인하면 :

ks.results <- apply(swaps, 2, function(col){ks.test(swaps[1,], col)})
p.values <- unlist(lapply(ks.results, function(x){x$p.value})

그리고 우리는 달려

hist(p.values, 100, col="black")

우리는 얻는다 :

Kolmogorov-Smirnov 검정 p 값의 히스토그램

따라서 배열의 대부분의 요소에 대해, 사 분위수를 볼 수 있듯이 스왑 방법은 좋은 결과를 얻었습니다.

1> quantile(p.values)
       0%       25%       50%       75%      100% 
0.6819832 0.9963731 0.9999188 0.9999996 1.0000000

시험 횟수가 적을수록 상황은 좋지 않습니다.

50 회 시도

1> quantile(p.values)
          0%          25%          50%          75%         100% 
0.0003399635 0.2920976389 0.5583204486 0.8103852744 0.9999165730

100 회 시도

          0%         25%         50%         75%        100% 
 0.001434198 0.327553996 0.596603804 0.828037097 0.999999591 

500 회 시도

         0%         25%         50%         75%        100% 
0.007834701 0.504698404 0.764231550 0.934223503 0.999995887 

0

의사 코드로 알고리즘을 해석하는 방법은 다음과 같습니다.

void shuffle(array, length, num_passes)
  for (pass = 0; pass < num_passes; ++pass) 
    for (n = 0; n < length; ++)
      i = random_in(0, length-1)
      j = random_in(0, lenght-1)
      swap(array[i], array[j]

2×이자형h×_에이에스에스이자형에스[0,이자형h1]이자형h

이자형h2×이자형h×_에이에스에스이자형에스

이자형h!이자형h!<이자형h2×이자형h×_에이에스에스이자형에스 따라서 일반적으로 주어진 순열은 둘 이상의 추적과 연관됩니다.

트레이스가 모두 균등할 가능성이 있으므로 모든 순열이 균등하게 될 수 있으려면 두 개의 순열이 동일한 수의 트레이스와 연결되어야합니다. 그것이 사실이라면, 우리는이자형h!|이자형h2×이자형h×_에이에스에스이자형에스.

소수를 선택하십시오 그런 <이자형h하지만 그런 이자형h, 당신은 어떤 일을 할 수 있습니다 이자형h>2. 그때|이자형h! 하지만 나누지 않습니다 이자형h2×이자형h×_에이에스에스이자형에스. 그것은 다음과 같습니다length!length2×length×num_passes and so all permutations cannot be equally likely if length>2.

Does such a prime exist? Yes. If length were divisible by all primes p<length, then length1 소수 여야하지만 이자형h1 작지만 나누지 않는 소수입니다 이자형h.

이것을 Fisher-Yates와 비교하십시오. 첫 번째 반복에서는 다음 중에서 선택합니다.이자형h옵션. 두 번째 반복은이자형h1옵션 등. 다시 말해 당신은이자형h! 흔적 이자형h!|이자형h!. 각 트레이스의 결과가 다른 순열을 나타내는 것은 어렵지 않으며 Fisher-Yates가 동일한 확률로 각 순열을 생성한다는 것을 쉽게 알 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.