php. Losowanie z prawdopodobieństwem.Sprawdzanie warunku.

0

Witam.
Sprawa wygląda następująco.
Losuję produkty z prawdopodobieństwem.
Sposób losowania wygląda następująco.
Suma prawdopodobieństw równa się jeden, załóżmy dla przykładu, że mam trzy produkty z odpowiadającymi im prawdopodobieństwami:
Pomarańcza = 0.6
Truskawka = 0.3
Inne = 0.1
Losuję liczbę z przedziału 0-1. Jak wypadnie 0-6 do pomarańcza, jak 7-9 truskawka itp.

Potrzebuję wylosować "x" elementów gdzie po sprawdzeniu prawdopodobieństwa do kolejnej tablicy przekazywana jest nazwa owocu.
Mam tablicę tej postaci:

Array
(
    [0] => Array
        (
            [Owoc] => PomaraĹcza
            [PrawdopodobieĹstwo] => 0.6
        )

    [1] => Array
        (
            [Owoc] => Truskawka
            [PrawdopodobieĹstwo] => 0.3
        )

    [2] => Array
        (
            [Owoc] => Inne
            [PrawdopodobieĹstwo] => 0.1
        )

)
1

Kod jaki napisałem:

<?php
$losowana = rand(0,10)/10;
$tablica = array();
$table = array(array('Owoc'=>'Pomarańcza', 'Prawdopodobieństwo'=>0.6), array('Owoc'=>'Truskawka', 'Prawdopodobieństwo'=>0.3),array('Owoc'=>'Inne', 'Prawdopodobieństwo'=>0.1));

echo '<pre>';
echo print_r($table);
echo '</pre>';

echo '<p>Losowana: '.$losowana.'</p>';
for($i=0; $i<10; $i++)
{
    $temp = rand(0,10)/10;
    if($temp<=0.6)
    {
        $tablica[$i]=$table[0]['Owoc'];
    }
    else if($temp>0.6 && $temp<=0.9)
    {
        $tablica[$i]=$table[1]['Owoc'];
    }
    else
    {
        $tablica[$i]=$table[2]['Owoc'];
    }
}


echo '<p>Tablica z prawdopodobieństwem</p>';
echo '<pre>';
echo print_r($tablica);
echo '</pre>';

Moim pytaniem jest jak to zoptymalizować przebudować tak, aby sprawdzało samo prawdopodobieństwo i wybierało dany owoc.
W tej chwili działa to głupio bo sam poprzypisywałem wartości do porównania oraz elementów jest mało.
Problem będzie jak pozmieniają się wartości prawdopodobieństwa, wtedy wszystko muszę zmieniać. Drugim problemem jest, że jak wzrośnie ilość produktów to nie będę pisał np. 100 if'ów.
Jak można to zoptymalizować przebudować.

0

Tu masz prosty przykład jaki robiłem kiedyś w js - możesz wypróbować go w konsoli przeglądarki (Ctrl+Shift+J). Jakbyś nie mógł zrozumieć to daj znać, postaram się wytłumaczyć, żebyś mógł to sobie przepisać na php:

var players = [], pot, result;

// funkcja oblicza sumę depozytów
// należy przekazać tablicę graczy i liczbę elementów do zsumowania
function calculateSum(itemsTable, range)
{
    var sum = 0;
    for(var i = 0; i < range; i++)
    {
        sum += itemsTable[i]['deposit'];
    }
    return sum;
}

// główna funkcja losująca zwycięzcę
// zwraca imię zwycięzcy
function runJackpot(itemsTable)
{
    var winner;
    pot = calculateSum(itemsTable, itemsTable.length);
    result = Math.floor(Math.random() * (pot + 1));
    for(var i = 0; i < itemsTable.length; i++)
    {
        if(result <= calculateSum(itemsTable, i + 1))
        {
            winner = itemsTable[i]['name'];
            return winner;
        }
    }
}

// ustawienie danych graczy (liczba graczy może być dowolna):

players[0] = {'name': 'Gracz1', 'deposit': 2500};
players[1] = {'name': 'Gracz2', 'deposit': 720};
players[2] = {'name': 'Gracz3', 'deposit': 50};
players[3] = {'name': 'Gracz4', 'deposit': 310};
players[4] = {'name': 'Gracz5', 'deposit': 1100};

// losowanie:

winner = runJackpot(players);

// prezentacja danych i wyniku (tutaj wyniki są pokazywane w konsoli):

for(var i = 0; i < players.length; i++)
{
  console.log('Imię: ' + players[i]['name'] + ' | Wkład: ' + players[i]['deposit']);
}
console.log('Pula: ' + pot);
console.log('Wylosowany los: ' + result); // tego w finalnym programie lepiej nie pokazywać
console.log('Zwycięzca: ' + winner);

Dla Twojego przypadku będzie to:

var fruit = [], pot, result;

function calculateSum(itemsTable, range)
{
    var sum = 0;
    for(var i = 0; i < range; i++)
    {
        sum += itemsTable[i]['deposit'];
    }
    return sum;
}

function runJackpot(itemsTable)
{
    var winner;
    pot = calculateSum(itemsTable, itemsTable.length);
    result = Math.floor(Math.random() * (pot + 1));
    for(var i = 0; i < itemsTable.length; i++)
    {
        if(result <= calculateSum(itemsTable, i + 1))
        {
            winner = itemsTable[i]['name'];
            return winner;
        }
    }
}

// ustawienie danych graczy (liczba graczy może być dowolna):

fruit[0] = {'name': 'Pomarancza', 'deposit': 60};
fruit[1] = {'name': 'Truskawka', 'deposit': 30};
fruit[2] = {'name': 'Inne', 'deposit': 10};

// losowanie:

winner = runJackpot(fruit);

// prezentacja danych i wyniku:

for(var i = 0; i < fruit.length; i++)
{
    console.log('Nazwa: ' + fruit[i]['name'] + ' | Prawdopodobieństwo wylosowania: ' + fruit[i]['deposit'] + '%');
}
console.log('Wszystkich losów: ' + pot);
console.log('Wylosowany los: ' + result);
console.log('Wylosowany owoc: ' + winner);
0

Dzięki za odpowiedź, analizuję, kod działa.
Postaram się przerobić teraz to na php sobie.

Chyba, że ktoś ma jeszcze inne propozycje.

0

No dobra, załóżmy że w tablicy byłby jakiś milion elementów :-) Jak długo zajęłoby przeszukiwanie takiej tablicy pod względem prawdopodobieństwa biorąc pod uwagę to że PHP jest w porównaniu z C po prostu koszmarnie powolne albo limity czasu wykonania skryptu? Może najpierw należałoby posortować jakoś te elementy a później szukać zaczynając od elementu w połowie, później odpowiednio przeskakiwać lewa połowa albo prawa połowa w zależności od wylosowanego prawdopodobieństwa? Nie chodzi tu chyba o każdorazowe skanowanie tablicy i o tysiące jak nie miliony kroków w pętli, zaczynając od zerowego indeksu :-) Robiłem tego typu szukanie na posortowanych tablicach, zaczynając od elementu w połowie, później kolejne podziały lewej albo prawej połowy znowu na pół itd, osiągając np. tylko 13 kroków a nie np. 1000 :-)

Coś podobnego jak np. ważenie, daję dla przykładu odważnik 5 kg, za mało na szali więc dodaję jeszcze odważnik 2 kg, wychodzi za dużo to zdejmuję i daję 1 kg a nie 2 kg, za mało to dodaję na szalę jeszcze 0.5 kg i jest równowaga.

Łapiesz o co mi chodzi? Tak to bym musiał dodawać podczas ważenia zaczynając od odważnika 500 g w każdym kolejnym kroku 500 g na szalę, to żeby zważyć ciężar 6,5 kg musiałbym wykonać 13 kroków, tutaj wyżej tylko w 4 krokach :-)

Funkcja sortowania tablicy po kluczu prawdopodobieństwa (tylko po co polskie znaki w nazwach kluczy?)

function cmp($a, $b)
{
    return $b['Prawdopodobienstwo'] - $a['Prawdopodobienstwo'];
}

usort($table, "cmp"); 

I masz posortowaną rosnąco tablicę po prawdopodobieństwie i tak możesz sobie szukać elementów w sposób podobny do tego ważenia co opisałem.

0

Przede wszystkim zacznij korzystać z funkcji mt_rand() zamiast rand(). http://php.net/manual/en/function.mt-rand.php

1 użytkowników online, w tym zalogowanych: 0, gości: 1