Aujourd'hui j'aimerais soumettre un problème à ta sagacité : celui du tirage aléatoire d'un élément dans un tableau.
Imaginons que je veuille tirer au hasard un élément dans un tableau qui en comporte N.
Je me souviens avoir lu quelque part qu'il suffit de faire :
1/N de prendre le premier sinon 2/N de prendre le second et ainsi de suite. Le dernier ayant une probabilité N/N d'être choisi si on arrive jusque là.
Cette solution à l'avantage d'être facile à implémenter cependant je n'arrive pas à démontrer que c'est vrai.
De plus, j'aimerais étendre ce principe à un dictionnaire qui comporte, pour chaque élément du tableau, une valeur qui est proportionnelle à la probabilité de prendre cet élément.
Exemple :
Considérons
{a : 1, b : 1, c : 2, d : 5, e :1}
La somme des valeurs des éléments vaut 10. d doit donc être choisi avec une probabilité 5/10, c avec une de 2/10, a,b et e avec une de 1/10.
Est-ce que l'implémentation suivant serait valable :
step = 0
sum = 10
for element in dictionnaire
{
step = step + element.value
nbr = random(0-10) % renvoie un nombre aléatoire entre 0 et 10
if nbr < step : choose element
else continue
}
Ainsi, dans notre exemple, il va choisir un nombre entre 0 et 10. Si ce nombre et 0, a va être choisi, step étant à 1.
Sinon, step devient 2 et un nouveau tirage est fait. Si le tirage est plus grand que 2, step devient direct 4. Un nouveau tirage est fait. si ça passe pas, step devient 9 et ainsi de suite.
Pensez-vous que cela soit correct ? Comment implémenteriez-vous un tel problème ?
Merci d'avance
# File dans ta chambre ...
Posté par Marc Poiroud (site web personnel) . Évalué à 10.
non mais ! ^_^
[^] # Re: File dans ta chambre ...
Posté par Serge Julien . Évalué à 2.
Une idée si tu n'as pas trop de valeurs (en Python, mais je suis sûr que tout bon langage a ce qu'il faut):
import random
1 - tu génères une liste avec des occurences en nombre égal aux poids dont tu disposes dans ton dictionnaire (supposons d={'a' : 1, 'b' : 1, 'c' : 2, 'd' : 5, 'e' :1}):
l = []
for x, y in d.items(): l.extend([x]*y)
2 - s'il s'agit de tirer au hasard un élément, il suffit de faire:
print random.choice(l)
3 - Si au contraire tu dois tirer tous les éléments:
random.shuffle(l)
for e in l: print e
Valà, si ça peut aider...
# Bah
Posté par Jb Evain (site web personnel) . Évalué à 5.
# Random mal placé
Posté par goeb . Évalué à 2.
Faire un tirage au sort tel que chaque élément a une probabilité propre d'être choisi (probabilité égale à sa valeur dans le tableau / somme totale).
Je pense que ton random est mal placé et devrait être fait une seule fois, avant la boucle, et que le reste est bon.
[^] # Re: Random mal placé
Posté par goeb . Évalué à 0.
Et c'était pareil sur un autre message dans un forum.
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à -3.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: Random mal placé
Posté par ploum (site web personnel, Mastodon) . Évalué à 1.
Mes livres CC By-SA : https://ploum.net/livres.html
# rand(0,count(tab) - 1)
Posté par Hardy Damien . Évalué à 0.
est ce que (en php) :
$tab = array('a','b','c','d','e','f','g','h','i');
echo $tab[ rand(0,count($tab)-1) ];
ne fait pas ce que tu veux ?
Dam
[^] # Re: rand(0,count(tab) - 1)
Posté par Hardy Damien . Évalué à 2.
une solution pourrait être de multiplié dans le tableau le element par la valeur de pondération associée qui deviendrait :
{a , b , c , c , d , d , d , d , d , e} et tu te retrouve avec le probleme qui trouve sa réponse dans mon post précédent non ?
Dam
[^] # Re: rand(0,count(tab) - 1)
Posté par ploum (site web personnel, Mastodon) . Évalué à 2.
C'est aussi relativement tout à fait inefficace en CPU et mémoire dans un problème ou ça doit être exécuté souvent (et récursivement)
Mes livres CC By-SA : https://ploum.net/livres.html
# faux
Posté par Kibos . Évalué à 4.
la probabilite P(i) de choisir 1 parmi N elements equiprobables est 1/N :
P(i)=1/N
D'apres ta methode, P(i)=P(not(i-1))*(i/N)
P(1)=1/N
P(2)=P(not(1))*(2/N)=(1-1/N)*(2/N)=(2*N-2)/(N*N) != 1/N
cqfd
[^] # Re: faux
Posté par ploum (site web personnel, Mastodon) . Évalué à 4.
Mes livres CC By-SA : https://ploum.net/livres.html
# En PHP
Posté par ondex . Évalué à 1.
[^] # Re: En PHP
Posté par andeus . Évalué à 0.
# euh....
Posté par yaya . Évalué à 2.
- 1er élément est a/10
- 2e élément est (1-a/10) * (a+b)/10
- 3e élément (1-(1-a/10) * (a+b)/10) * (a+b+c)/10
- etc...
il me semble que pour que ton algo soit correct, il faut tirer un seul nombre aléatoire au début et trouver l'élément pour lequel la somme cumulée est supérieur au nombre aléatoire...
step = 0
sum = 10
nbr = random(0-10) % renvoie un nombre aléatoire entre 0 et 10
for element in dictionnaire
{
step = step + element.value
if nbr < step : choose element
else continue
}
alors, la proba de tirer le
- 1er élément est a/10
- 2e élément est (a+b)/10 - a/10 = b/10
- 3e élément (a+b+c)/10 - (a+b)/10 = c/10
- etc...
enfin si je ne me suis pas planté...
# Pas compris ton algo
Posté par Nicolas Schoonbroodt . Évalué à 0.
Je ne suis surement pas bien attentif, mais j'ai pas bien compris ton algo. Personnellement, je vois une adaptation simple de l'algo dont tu te souviens. (1/N, 2/N, ...) J'espère que mon raisonement ne tombe pas sur ton algo.
Il suffit de considérer que tu as un tableau de longueur (somme des tes proportionalités)
Tu le remplit comme ceci :
a, b, c, c, d, d, d, d, d, e
Ensuite tu applique cet algo dessus.
Donc dans la case 1, 1/10, dans la case 2, 2/10, ...
Maintenant, si on formalise ceci, on passe de ton tableau original :
{a : 1, b : 1, c : 2, d : 5, e :1}
en un tableau de la forme (c'est du pseudo-LaTeX)
{v_1 : p_1, v_2 : p_2, ... v_n : p_n }
ce tableau se transforme en un autre tableau de taille S = \sum_i p_i :
{v_1, v_1, ... v_2, v_2, ... v_n, v_n }
avec comme probabilité de tirage de chaque élément seul pos_i / S (avec pos_i la position dans le tableau)
Maintenant, arrangeons la formule.
Pour le premier élément, la probabilité de le tirer est :
P = sum_{i=1}^{p_1} i/S
Pour l'élément n : (valable pour n = 1)
P = sum_{i=1}^{p_n} (X+i)/S avec X=sum_{j=1}^(n-1) p_j (si n=1, X = 0)
Ensuite, on applique les propriétés des séries "je ne sais plus le nom", on on obtient :
P = (2X + p_n + 1) / 2S
Mmmm je ne suis évidement pas sur, mais avec p_i = 1 pour tout i, on retombe sur ta formule dans le cas de probabilités égales (ouf). Je ne suis même pas sur que c'est cela que tu veux.
[^] # Re: Pas compris ton algo
Posté par Nicolas Schoonbroodt . Évalué à -1.
[^] # Re: Pas compris ton algo
Posté par Hrundi V. Bakshi . Évalué à 1.
Moi j'aurais un tableau contenant les nombre et leur coef, et avec un nombre aléatoire tiré entre 0 et la somme des coefs, je rechercherais le nombre en m'arretant dès que que j'ai une somme de coef égalant mon nombre aléatoire.
S <- somme des coefficients.
x <- random * S (random retournant un nb entre 0 et 1)
i<- 0
p<-pondération[i]
Tant que(p!=x) {
i++
p<-p+pndération[i]
}
ecrire ( "le nombre tiré est")
écrire ( nombre[i])
Voilà approximattivement ce que je ferais.
[^] # Re: Pas compris ton algo
Posté par Hrundi V. Bakshi . Évalué à -1.
Mais c'est à mon avis la bonne soluttion.
# Premier cas :
Posté par Thomas Douillard . Évalué à 1.
si tu tombe sur un nombre entre 0/N et 1/N, tu choisis le premier, entre 1/N et 2/N, le second, etc.
Après, suffit de faire un trux du genre trunc(alea()*N) pour trouver l'indice.
[0..1/N[ * N -> [0..1[ -> trunc -> 0
[(N-1)/N .. 1] * N -> [N-1 .. N[ -> trunc -> N-1
si je me trompe pas.
# Forums
Posté par proum . Évalué à 2.
[^] # Re: Forums
Posté par Krunch (site web personnel) . Évalué à 5.
https://linuxfr.org/forums/19/3252.html
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Forums
Posté par ploum (site web personnel, Mastodon) . Évalué à 0.
Mes livres CC By-SA : https://ploum.net/livres.html
[^] # Re: Forums
Posté par Krunch (site web personnel) . Évalué à 3.
Ce dont je ne me souvenais pas c'est de ce post là par contre : http://linuxfr.org/~ploum/12754.html#413047
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
# Faux, absurde et debordement
Posté par Jerome Herman . Évalué à 4.
1ere passe
-debut : step = 0
-entre dans la boucle for
step = 0+1 = 1
nbr dans {0-10}
element[0] choisit si nbr=0 (une chance sur onze, ca part mal)
probablitié de choix de element[0]: 1/11
2eme passe (si nbr<>0)
- debut step=1
- boucle : step=1+1=2
nbr dans {0-10}
element[1] choisit si nbr<2 (deux chances sur onze, on est pas beau)
probabilité de choix de element[1] : 10/11*2/11=20/121 (le premier nbr n'est pas 0 et le second est 0 ou 1)
3eme passe (si nbr<>0 puis nbr<>0 et nbr<>1)
-debut step=2
- boucle : step=2+2=4
nbr dans {0-10}
element[2] choisit si nbr<4 (4 chances sur 11)
probabilité de choix de l'element[2] : 10/11*9/11*4/11= 360/1331 ( premier nbr différent de 0, deuxième nbr différent de 0 ou 1, troisième nbr est 0,1,2 ou 3)
etc.
Allez une solution qui marche en pseudo code :
$total=0;
pour $element dans $dico
($total=$total+$element.valeur;)
fin pour;
$index=aleatoire(1-$total); #nombre entier aléatoire entre 1 et $total inclus
$i=1;
$postition=0;
tant que $i<$index
($i=$i+$dictionnaire[$position].valeur;
$position=$position+1;)
fin tant que;
renvoit $position;
Dans le cas particulier cité en exemple on aura bien un $total à 10
donc $index sera compris entre 1 et 10
si $index vaut 1 : pas d'execution de la boucle (1<1 est faux), le système renvoit $postion=0
La position 0 a une chance sur 10 d'être choisie ($index=1)
si $index vaut 2, un passage dans la boucle (1<2 est vrai), $i passe à 2 (1+$dictionnaire[0].valeur) et pas de deuxième passage dans la boucle. Le système renvoit $position=1
La position 1 a une chance sur dix d'être choisie ($index=2)
si index vaut 3 ou 4 : 2 passage dans la boucle :
init : $i=1
première passe : $i=2
seconde passe : $i=4 et (4<4 est faux)
Le système renvoit $position=2
la position 3 a deux chances sur dix d'être choisie ($index=3 ou $index=4)
etc.
[^] # Re: Faux, absurde et debordement
Posté par André Rodier . Évalué à -8.
Va boire un peu d'eau, c'est les vacances et il fait chaud...
[^] # Petites fleurs, papillons et lapins roses
Posté par Jerome Herman . Évalué à 2.
Je fais une thèse qui vise à démontrer que la notation obtenue sur Linuxfr est uniquement liée au titre du post sans quasiment aucun rapport avec le contenu. Merci de ta participation au fait.
[^] # Britney, ponies, RMS, Merdrake, moustache
Posté par zerchauve . Évalué à -3.
# tu copieras 100 fois dans ta console
Posté par alice . Évalué à 6.
Avec les consonnes en rouge et les voyelles en vert.
[^] # Re: tu copieras 100 fois dans ta console
Posté par Christophe Chailloleau-Leclerc . Évalué à 3.
[^] # Re: tu copieras 100 fois dans ta console
Posté par Christophe Chailloleau-Leclerc . Évalué à 1.
[^] # Re: tu copieras 100 fois dans ta console
Posté par Krunch (site web personnel) . Évalué à 4.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: tu copieras 100 fois dans ta console
Posté par Christophe Chailloleau-Leclerc . Évalué à 2.
/me se flagelle avec des orties fraiches !
Bon, pour plus court, c'est clair, mais là j'suis dans du C et du C++ en ce moment, alors j'ai fait au plus "rapide" sans réfléchir ;)
[^] # Re: tu copieras 100 fois dans ta console
Posté par EdB . Évalué à 0.
Évidemment il faut voir si ton système doit privilégier la consomation mémoire ou la consomation cpu :þ
[^] # Re: tu copieras 100 fois dans ta console
Posté par Christophe Chailloleau-Leclerc . Évalué à 3.
[^] # Re: tu copieras 100 fois dans ta console
Posté par Marc Poiroud (site web personnel) . Évalué à 2.
surement ;)
$ vim punition
Je ne ferais pas faire mes projets par mes petits camarades.
~
~
yy
99p
:wq
$ cat punition
Enjoy :p
[^] # Re: tu copieras 100 fois dans ta console
Posté par lezardbreton . Évalué à 2.
[^] # Re: tu copieras 100 fois dans ta console
Posté par Marc Poiroud (site web personnel) . Évalué à 2.
[^] # Re: tu copieras 100 fois dans ta console
Posté par M . Évalué à 3.
pff c'est encore trop long ;)
yes "Je ne ferais pas faire mes projets par mes petits camarades." | head -100 > punition
[^] # Re: tu copieras 100 fois dans ta console
Posté par Krunch (site web personnel) . Évalué à 2.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
# alternative arboricole
Posté par Krunch (site web personnel) . Évalué à 4.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: alternative arboricole
Posté par Contre . Évalué à -1.
pas scheme !!!!
(ce commentaire est, peut-être, "optimisé" > 1280x1024)
# tu avais du lire
Posté par mac_is_mac (site web personnel) . Évalué à 5.
1/N de prendre le premier sinon 2/N de prendre le second et ainsi de suite. Le dernier ayant une probabilité N/N d'être choisi si on arrive jusque là."
En fait, tu avais du lire:
1/N de prendre le premier sinon 1/(N-1) de prendre le second et ainsi de suite. Le dernier ayant une probabilité 1/1 d'être choisi si on arrive jusque là."
[^] # Re: tu avais du lire
Posté par ploum (site web personnel, Mastodon) . Évalué à 1.
Mes livres CC By-SA : https://ploum.net/livres.html
[^] # Re: tu avais du lire
Posté par Matthieu Moy (site web personnel) . Évalué à 2.
T'imagines un segment de longueur « somme des coefficients », fait de la concaténation de segments de longueur chaque coefficients. Tu tires un point au hasard, uniformément dans ce segment. Bon, doit y avoir plus formel comme démo, mais ...
[^] # Re: tu avais du lire
Posté par mac_is_mac (site web personnel) . Évalué à 2.
P(X>k)=(1-1/N)(1-1/(N-1))(1-(1/N-2))...(1-1/(N-k+1))
=(N-1)/N.(N-2)/(N-1).(N-3)/(N-2)....(N-k)/(N-k+1)
=(N-k)/N
D'où
P(X=k)=P(X>k-1)-P(X>k)
=(N-k+1)/N-(N-k)/N=1/N
[^] # Re: tu avais du lire
Posté par Matthieu Moy (site web personnel) . Évalué à 3.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.