Random weighted choice

numpy weighted choice
python weighted random sample without replacement
random function
python choose with probability
python random two choices
python random triangular
python random choice empty list
random pick with weight python

Consider the class below that represents a Broker:

public class Broker
{
    public string Name = string.Empty;
    public int Weight = 0;

    public Broker(string n, int w)
    {
        this.Name = n;
        this.Weight = w;
    }
}

I'd like to randomly select a Broker from an array, taking into account their weights.

What do you think of the code below?

class Program
    {
        private static Random _rnd = new Random();

        public static Broker GetBroker(List<Broker> brokers, int totalWeight)
        {
            // totalWeight is the sum of all brokers' weight

            int randomNumber = _rnd.Next(0, totalWeight);

            Broker selectedBroker = null;
            foreach (Broker broker in brokers)
            {
                if (randomNumber <= broker.Weight)
                {
                    selectedBroker = broker;
                    break;
                }

                randomNumber = randomNumber - broker.Weight;
            }

            return selectedBroker;
        }


        static void Main(string[] args)
        {
            List<Broker> brokers = new List<Broker>();
            brokers.Add(new Broker("A", 10));
            brokers.Add(new Broker("B", 20));
            brokers.Add(new Broker("C", 20));
            brokers.Add(new Broker("D", 10));

            // total the weigth
            int totalWeight = 0;
            foreach (Broker broker in brokers)
            {
                totalWeight += broker.Weight;
            }

            while (true)
            {
                Dictionary<string, int> result = new Dictionary<string, int>();

                Broker selectedBroker = null;

                for (int i = 0; i < 1000; i++)
                {
                    selectedBroker = GetBroker(brokers, totalWeight);
                    if (selectedBroker != null)
                    {
                        if (result.ContainsKey(selectedBroker.Name))
                        {
                            result[selectedBroker.Name] = result[selectedBroker.Name] + 1;
                        }
                        else
                        {
                            result.Add(selectedBroker.Name, 1);
                        }
                    }
                }


                Console.WriteLine("A\t\t" + result["A"]);
                Console.WriteLine("B\t\t" + result["B"]);
                Console.WriteLine("C\t\t" + result["C"]);
                Console.WriteLine("D\t\t" + result["D"]);

                result.Clear();
                Console.WriteLine();
                Console.ReadLine();
            }
        }
    }

I'm not so confident. When I run this, Broker A always gets more hits than Broker D, and they have the same weight.

Is there a more accurate algorithm?

Thanks!

Your algorithm is nearly correct. However, the test should be < instead of <=:

if (randomNumber < broker.Weight)

This is because 0 is inclusive in the random number while totalWeight is exclusive. In other words, a broker with weight 0 would still have a small chance of being selected – not at all what you want. This accounts for broker A having more hits than broker D.

Other than that, your algorithm is fine and in fact the canonical way of solving this problem.

random-weighted-choice, Node.js module to make a random choice among weighted elements of table. def weightedChoice(choices): """Like random.choice, but each element can have a different chance of being selected. choices can be any iterable containing iterables with two items each. Technically, they can have more than two items, the rest will just be ignored. The first item is the thing being chosen, the second item is its weight.

How about something a little more generic, that can be used for any data type?

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;

public static class IEnumerableExtensions {

    public static T RandomElementByWeight<T>(this IEnumerable<T> sequence, Func<T, float> weightSelector) {
        float totalWeight = sequence.Sum(weightSelector);
        // The weight we are after...
        float itemWeightIndex =  new Random().NextDouble() * totalWeight;
        float currentWeightIndex = 0;

        foreach(var item in from weightedItem in sequence select new { Value = weightedItem, Weight = weightSelector(weightedItem) }) {
            currentWeightIndex += item.Weight;

            // If we've hit or passed the weight we are after for this item then it's the one we want....
            if(currentWeightIndex >= itemWeightIndex)
                return item.Value;

        }

        return default(T);

    }

}

Simply call by

    Dictionary<string, float> foo = new Dictionary<string, float>();
    foo.Add("Item 25% 1", 0.5f);
    foo.Add("Item 25% 2", 0.5f);
    foo.Add("Item 50%", 1f);

    for(int i = 0; i < 10; i++)
        Console.WriteLine(this, "Item Chosen {0}", foo.RandomElementByWeight(e => e.Value));

Python Weighted random choices from the list with Probability, Implement weighted random choices in Python. Choose elements from the list randomly with a different probability. A Faster Weighted Random Choice Linear Scan. The simplest algorithm works by generating a random number and walking along the list of weights in a Binary Search. With a little bit of preprocessing, it's possible to speed up the algorithm by storing the running totals Hopscotch Selection.

class Program
{
    static void Main(string[] args)
    {
        var books = new List<Book> {
        new Book{Isbn=1,Name="A",Weight=1},
        new Book{Isbn=2,Name="B",Weight=100},
        new Book{Isbn=3,Name="C",Weight=1000},
        new Book{Isbn=4,Name="D",Weight=10000},
        new Book{Isbn=5,Name="E",Weight=100000}};

        Book randomlySelectedBook = WeightedRandomization.Choose(books);
    }
}

public static class WeightedRandomization
{
    public static T Choose<T>(List<T> list) where T : IWeighted
    {
        if (list.Count == 0)
        {
            return default(T);
        }

        int totalweight = list.Sum(c => c.Weight);
        Random rand = new Random();
        int choice = rand.Next(totalweight);
        int sum = 0;

        foreach (var obj in list)
        {
            for (int i = sum; i < obj.Weight + sum; i++)
            {
                if (i >= choice)
                {
                    return obj;
                }
            }
            sum += obj.Weight;
        }

        return list.First();
    }
}

public interface IWeighted
{
    int Weight { get; set; }
}

public class Book : IWeighted
{
    public int Isbn { get; set; }
    public string Name { get; set; }
    public int Weight { get; set; }
}

How to get a weighted random choice in Python, A weighted random choice will return a random element in a list according to its weight in the list. Higher weight elements have a higher chance of getting selected. random-weighted-choice(Array table, Number temperature = 50) Return the id of the chosen item from table. The table parameter should contain an Array. Each item of that Array must bean object, with at least weight and id property. Weight values are relative to each other. They are integers.

An alternative method favours speed when selecting the broker over memory usage. Basically we create the list containing the same number of references to a broker instance as the specified weight.

List<Broker> brokers = new List<Broker>();
for (int i=0; i<10; i++)
    brokers.Add(new Broker("A", 10));
for (int i=0; i<20; i++)
    brokers.Add(new Broker("B", 20));
for (int i=0; i<20; i++)
    brokers.Add(new Broker("C", 20));
for (int i=0; i<10; i++)
    brokers.Add(new Broker("D", 10));

Then, to select a randomly weighted instance is an O(1) operation:

int randomNumber = _rnd.Next(0, brokers.length);
selectedBroker = brokers[randomNumber];

Numerical & Scientific Computing with Python: Weighted Choice , Weighted Sample. In the previous chapter on random numbers and probability, we introduced the function 'sample' of the module 'random' to randomly extract a � def weightedChoice(choices): """Like random.choice, but each element can have a different chance of being selected. choices can be any iterable containing iterables with two items each. Technically, they can have more than two items, the rest will just be ignored. The first item is the thing being chosen, the second item is its weight.

A Faster Weighted Random Choice - Naming Things, You want to randomly choose an item, with probability proportional to the item's weight. For these examples, the algorithms will take a list of� Weighted Random Choice with Numpy. To produce a weighted choice of an array like object, we can also use the choice function of the numpy.random package. Actually, you should use functions from well-established module like 'NumPy' instead of reinventing the wheel by writing your own code. In addition the 'choice' function from NumPy can do even more.

Weighted random choice in Python, There are two tiny issues I'd like to address today: first, there is no method in Python's random module for weighted random choice; second, I haven't posted� Random weighted text value. To return a random weighted text value (i.e. a non-numeric value), you can enter text values in the range B5:B10, then add INDEX to return a value in that range, based on the position returned by MATCH: =

parmentf/random-weighted-choice: Node.js module to , Node.js module to make a random choice among weighted elements of table. - parmentf/random-weighted-choice. Paste or type out all the items that you want to choose from in the box below and then click the Random Choice button. The randomly generated item from the list will appear just below the text box. The randomly generated item from the list will appear just below the text box.

numpy.random.choice — NumPy v1.10 Manual, If an ndarray, a random sample is generated from its elements. If an int, the random sample is generated as if a was np.arange(n). size : int or tuple of ints,� Weighted random choice makes you able to select a random value out of a set of values using a distribution specified though a set of weights. So, given a list we want to pick randomly some elements from it but we need that the chances to pick a specific element is defined using a weight.

Comments
  • Hello sir, I saw your question and got inspired to create my own adrotator class in Java using your algorithm. I kindly request you to explain how you would select the brokers from the database if you had a million brokers on the database stored in a wide row. Will I select the first n and apply your algorithm to pick a random broker and on the next request select the next n brokers starting from n+1 and so on?
  • I wrote a library along very similar lines... It's has a few additional features, and it's optimized for large data sets: github.com/kinetiq/Ether.WeightedSelector
  • Do your brokers need to be sorted by weight ascending?
  • will this also work with weights that are double precision values?
  • @Jordan It will, up to the precision of double. However, the above code uses _rnd.Next which only works on integer ranges. To use a double range, you need to use the appropriate method for generating a number from a double range.
  • I know. Random has a NextDouble method that returns a double between 0.0 and 1.0. I can just multiply this value by the total weight. :) Thanks.
  • Every time you do new Random() it is initialized using the clock. This means that in a tight loop you get the same value lots of times. You should keep a single Random instance and keep using Next on the same instance. Therefor, make a class level declaration for the Random instance.
  • I'm also wondering why the need for the inner for loop? Wouldn't just adding weight to sum and checking whether it's >= to choice work as well?
  • Yet another alternative that won't cost so much memory would be to use indexes into the Broker array.
  • Is it just me or will that loop always choose the first item on the first iteration
  • @Epirocks It will temporarily, but then it has a chance of overwriting it in a subsequent iteration.