1

Je simule le modèle où il y a N billes, desquelles les billes K sont bonnes. Nous sélectionnons n billes sur N billes et on nous demande la probabilité que exactement k sur les n cueillies sont bonnes. J'ai fait cela de deux façons: Dans les deux, j'ai généré un tableau contenant K 'true' valeurs et N-K 'false' valeurs. Mais dans la première méthode j'ai mélangé ce tableau et j'ai choisi les n premières valeurs et j'ai compté combien d'entre elles sont 'vraies'. Dans la deuxième méthode, j'ai choisi un index au hasard et j'ai retiré cet élément du tableau, en le bouclant n fois (et en comptant bien sûr les éléments 'vrais' que j'ai obtenus).Simulation hypergéométrique, cueillir tout à la fois en remuant une fois donne un mauvais résultat

La distribution résultante doit être HyperGeometric(N, K, n). La première méthode m'a donné de mauvais résultats alors que la seconde a donné le bon résultat. Pourquoi n'est-il pas acceptable de choisir les n premiers éléments de la matrice mélangée ou quoi d'autre ai-je tort? Voici mon code Javascript:

function pickGoodsTest(N, K, n) { 
    var origArr = generateArr(N, i=> i<K); 
    shuffle(origArr); 
    var goods = 0; 
    for (let i=0; i<n; i++) if(origArr[i]) goods++; 
    return goods; 
} 

function pickGoodsTest2(N, K, n) { 
    var origArr = generateArr(N, i=> i<K); 
    var goods = 0; 
    for (let i=0; i<n; i++) { 
     let rndInd = randInt(0, origArr.length-1); 
     let wasGood = origArr.splice(rndInd, 1)[0]; 
     if (wasGood) goods++; 
    } 
    return goods; 
} 

//helper functions: 

function generateArr(len, indFunc) { 
    var ret = []; 
    for (let i=0; i<len; i++) { 
     ret.push(indFunc(i)); 
    } 
    return ret; 
} 

function randInt(a, b){return a+Math.floor(Math.random()*(b-a+1));} 

function shuffle(arr) { 
    let arrLen = arr.length; 
    for (let i=0; i<arrLen; i++) { 
     let temp = arr[i]; 
     let rndInd = randInt(0, arrLen-1); 
     arr[i] = arr[rndInd]; 
     arr[rndInd] = temp; 
    } 
} 

Ce sont des parcelles des résultats avec des valeurs N = 10, K = 6, n = 5 (simulés 500000 fois):

enter image description here

Le point jaune est la valeur de l'pmf hypergéométrique.

Répondre

3

La façon dont vous mélangez le tableau est biaisé, je suggère d'utiliser Fisher-Yates Shuffle à la place:

function shuffle(arr) { 
    let arrLen = arr.length; 
    for (let i=0; i<arrLen; i++) { 
     let temp = arr[i]; 
     let rndInd = randInt(0, i); 
     arr[i] = arr[rndInd]; 
     arr[rndInd] = temp; 
    } 
} 
+0

Merci! J'ai toujours utilisé l'ancienne façon de mélanger sans penser si elle est biaisée. Le shuffle de Fisher-Yates produit le résultat correct (comme prévu, puisqu'il est impartial comme le dit Wikipedia). – ploosu2

3

Le code ci-dessous prouve que votre mécanisme de lecture aléatoire est erroné. Code remixe un tableau de taille 3 dans tous les résultats possibles de hasard et recueille des statistiques de chance pour qu'un nombre soit dans la position spécifique.

import java.util.Arrays; 

public class TestShuffle { 
    public static void main(String[] args) { 
     int[][] stat = new int[3][3]; 

     for (int i = 0; i < 3; i++) { 
      for (int j = 0; j < 3; j++) { 
       for (int k = 0; k < 3; k++) { 
        int[] y = {0, 1, 2}; 
        swap(y, 0, i); 
        swap(y, 1, j); 
        swap(y, 2, k); 

        stat[0][y[0]]++; 
        stat[1][y[1]]++; 
        stat[2][y[2]]++; 
       } 
      } 
     } 

     System.out.println(Arrays.deepToString(stat)); 
    } 

    private static void swap(int[] y, int i, int k) { 
     int tmp = y[i]; 
     y[i] = y[k]; 
     y[k] = tmp; 
    } 
} 

sortie est

[[9, 10, 8], [9, 8, 10], [9, 9, 9]] 

Cela signifie que la possibilité pour le nombre "1" pour être dans la position 0 est supérieur à 1/3. C'est 10/27.