frank-houweling/weighted-random

Library for generating a weighted random sample

1.0.1 2019-07-27 18:59 UTC

This package is auto-updated.

Last update: 2024-04-28 06:27:52 UTC


README

Build Status codecov

This library is used to pick random values from a set of registered values, where values with a higher weight have a larger probability to be picked.

Installing

Install this library using composer.

composer require frank-houweling/weighted-random

Getting started

Using this library is simple. Initiate the WeightedRandomGenerator, register the possible values, and start generating random values!

<?php
use FrankHouweling\WeightedRandom\WeightedRandomGenerator;

// Initiate the generator
$generator = new WeightedRandomGenerator();

// Register some value
$generator->registerValue('foobar', 5);

// And get a random value
echo $generator->generate() . PHP_EOL;

Registering values

You can set one value with its weight using the following method. A higher weight means a higher probability that the value is generated by the random generator.

<?php
use FrankHouweling\WeightedRandom\WeightedRandomGenerator;

// Initiate the generator
$generator = new WeightedRandomGenerator();

// Register a new value
$generator->registerValue('foobar', 5);

// Override the added value with a weight of 1
$generator->registerValue('foobar', 1);

// The weight should be above 0, this call will result in an \InvalidArgumentException
$generator->registerValue('foobar', 0);

You can register multiple values at once with the registerValues() method. This method only accepts strings an integers as values.

The registerValues() methods expects the value to be the key, and the weight to be the value of the passed array.

<?php
use FrankHouweling\WeightedRandom\WeightedRandomGenerator;

$generator = new WeightedRandomGenerator();

// Register multiple values
$generator->registerValues([
    'foo' => 1,
    'bar' => 2,
]);

// Override the bar, foo will stay the same.
$generator->registerValues([
    'bar' => 1,
]);

// This will result in an InvalidArgumentException, 0 is not a correct weight.
$generator->registerValues([
    'bar' => 0,
]);

You can remove a value from the generator with the removeValue method.

<?php
use FrankHouweling\WeightedRandom\WeightedRandomGenerator;

$generator = new WeightedRandomGenerator();
$generator->registerValue('foobar', 2);

$generator->removeValue('foobar');

If you prefer, you can also use the WeightedValue valueobject. You should use the registerWeightedValue and removeWeightedValue methods to register and remove values with these value objects.

<?php
use FrankHouweling\WeightedRandom\WeightedRandomGenerator;
use FrankHouweling\WeightedRandom\WeightedValue;

$generator = new WeightedRandomGenerator();

$weightedValue = new WeightedValue('foobar', 2);
$generator->registerWeightedValue($weightedValue);
$generator->removeWeightedValue($weightedValue);

Retrieving registered values

You can retrieve registered values and their weights from the generator. These are always returns as WeightedValue valueobjects.

<?php
use FrankHouweling\WeightedRandom\WeightedRandomGenerator;

$generator = new WeightedRandomGenerator();
$generator->registerValues([
    'foo' => 2,
    'bar' => 3,
]);

// Retrieve all registered values
foreach ($generator->getWeightedValues() as $weightedValue) {
    echo sprintf(
        '%s => %s',
        $weightedValue->getValue(),
        $weightedValue->getWeight()
    ) . PHP_EOL;
}

// Or only one, by the given value.
$weightedValue = $generator->getWeightedValue('foo');
echo $weightedValue->getWeight() . PHP_EOL;

Generating a random sample

To generate a random sample from the registered values, we use the generate method.

Generated values are not always unique. It is possible that calling the generate method twice will return in the same value twice.

<?php
use FrankHouweling\WeightedRandom\WeightedRandomGenerator;

$generator = new WeightedRandomGenerator();
$generator->registerValue('foo', 2);

// Because we only registered one value, this now always returns `foobar`
echo $generator->generate() . PHP_EOL;

$generator->registerValue('bar', 2);

// Because we have registered two values, both with a weight of 2, the chance of foo and bar is both 50%.
echo $generator->generate() . PHP_EOL;

You can also generate a sample of multiple values using the generateMultiple method, and a set of multiple values without a possibility of duplicates with generateMultipleWithoutDuplicates.

<?php
use FrankHouweling\WeightedRandom\WeightedRandomGenerator;

$generator = new WeightedRandomGenerator();
$generator->registerValues([
    'foo' => 2,
    'bar' => 2,
]);

// Can return foo + bar, bar + foo, foo + foo or bar + bar.
foreach ($generator->generateMultiple(2) as $value) {
    echo $value . PHP_EOL;
}

// Can return foo + bar or bar + foo
foreach ($generator->generateMultipleWithoutDuplicates(2) as $value) {
    echo $value . PHP_EOL;
}

// This will return three values, of which 2 or 3 are duplicate.
$generator->generateMultiple(3);

// This will throw an \InvalidArgumentException, because it is not possible to generate three unique values.
$generator->generateMultipleWithoutDuplicates(3);